scala中的option[T]、Any、Nothing、Null、null、Nil、None、Some和Unit
scala中的option[T]、Any、Nothing、Null、null、Nil、None和Unit
1 Option[T] 、 None 和 Some
Option定義:
package scala @scala.SerialVersionUID(value = -114498752079829388) sealed abstract class Option[+A]() extends scala.AnyRef with scala.Product with scala.Serializable { ... } object Option extends scala.AnyRef with scala.Serializable { implicit def option2Iterable[A](xo : scala.Option[A]) : scala.Iterable[A] = { /* compiled code */ } def apply[A](x : A) : scala.Option[A] = { /* compiled code */ } def empty[A] : scala.Option[A] = { /* compiled code */ } }
Option[T]主要是用來避免NullPointerException異常的(Option本身是一個容器)
object Test { def main(args: Array[String]): Unit = { val option1: Option[Int] = Some(2018) val option2: Option[Int] = None val v1 = option1.getOrElse(0) println(v1)//輸出:2018 val v2 = option2.getOrElse(0) println(v2)//輸出: 0 //我們明確知道option1是有值的 val v3 = option1.get println(v3)//輸出:2018 val map:Map[Int,String] = Map(1 -> "aaa", 2 -> "bbbb", 3 -> "cccc") //根據key獲取map中的值,map中的value都是一個Option val v4:Option[String] = map.get(1) println(v4)//輸出:Some(aaa) //根據key獲取map中的值,並求出值的長度 println(map.get(1).getOrElse("").length())//輸出:3 println(map.get(10).getOrElse("").length())//輸出:0 println(map.get(10))//輸出:None //檢測Option容器中的元素是否為 None println(map.get(1).isEmpty)//輸出:false println(map.get(10).isEmpty)//輸出:true } }
Option定義了getOrElse方法,在獲取容器中的值是如果有返回容器中的值,如果沒有就返回給定的值,這一點和Java8的一樣。
Option定義了get方法,直接獲取容器中的元素,該操作不安全,可能會遇到None,None呼叫get就會出現空指標異常
Option定義了isEmpty方法,可以判斷容器中是不是None
Option的apply()方法可以返回None/Some可知None或Some必定是Option的子類,None與Some原始碼
None 原始碼 package scala @scala.SerialVersionUID(value = 5066590221178148012) case object None extends scala.Option[scala.Nothing] with scala.Product with scala.Serializable { def isEmpty : scala.Boolean = { /* compiled code */ } def get : scala.Nothing = { /* compiled code */ } } Some原始碼 package scala @scala.SerialVersionUID(value = 1234815782226070388) final case class Some[+A](val value : A) extends scala.Option[A] with scala.Product with scala.Serializable { def isEmpty : scala.Boolean = { /* compiled code */ } def get : A = { /* compiled code */ } @scala.deprecated("Use .value instead.", "2.12.0") def x : A = { /* compiled code */ } }
Option的常用方法:
序號 | 方法及描述 |
---|---|
1 | def get: A 獲取可選值 |
2 | def isEmpty: Boolean 檢測可選型別值是否為 None,是的話返回 true,否則返回 false |
3 | def productArity: Int 返回元素個數, A(x_1, ..., x_k), 返回 k |
4 | def productElement(n: Int): Any 獲取指定的可選項,以 0 為起始。即 A(x_1, ..., x_k), 返回 x_(n+1) , 0 < n < k. |
5 | def exists(p: (A) => Boolean): Boolean 如果可選項中指定條件的元素存在且不為 None 返回 true,否則返回 false。 |
6 | def filter(p: (A) => Boolean): Option[A] 如果選項包含有值,而且傳遞給 filter 的條件函式返回 true, filter 會返回 Some 例項。 否則,返回值為 None 。 |
7 | def filterNot(p: (A) => Boolean): Option[A] 如果選項包含有值,而且傳遞給 filter 的條件函式返回 false, filter 會返回 Some 例項。 否則,返回值為 None 。 |
8 | def flatMap[B](f: (A) => Option[B]): Option[B] 如果選項包含有值,則傳遞給函式 f 處理後返回,否則返回 None |
9 | def foreach[U](f: (A) => U): Unit 如果選項包含有值,則將每個值傳遞給函式 f, 否則不處理。 |
10 | def getOrElse[B >: A](default: => B): B 如果選項包含有值,返回選項值,否則返回設定的預設值。 |
11 | def isDefined: Boolean 如果可選值是 Some 的例項返回 true,否則返回 false。 |
12 | def iterator: Iterator[A] 如果選項包含有值,迭代出可選值。如果可選值為空則返回空迭代器。 |
13 | def map[B](f: (A) => B): Option[B] 如果選項包含有值, 返回由函式 f 處理後的 Some,否則返回 None |
14 | def orElse[B >: A](alternative: => Option[B]): Option[B] 如果一個 Option 是 None , orElse 方法會返回傳名引數的值,否則,就直接返回這個 Option。 |
15 | def orNull 如果選項包含有值返回選項值,否則返回 null。 |
2 Any
Any是abstract類,它是Scala類繼承結構中最底層的。所有執行環境中的Scala類都是直接或間接繼承自Any這個類,它就是其它語言(.Net,Java等)中的Object。
Any 處於型別結構樹的根部位置,Any 沒有父類,但有三個子類:
AnyVal, 價值型別和價值類的父類。
AnyRef,所有引用型別的父類。
•通用特徵(universal trait)。
AnyVal 有九個具體子類,稱為值型別。其中七個是數字值型別:Byte、Char、Short、Int、Long、Float 和Double。餘下的兩個是非數字值型別,Unit 和Boolean。
除AnyVal及其子類外,其他型別均為引用型別。它們派生自AnyRef,AnyRef 是java.lang.Object的別名。在Java 的物件模型中,Object 並沒有一個封裝了原生型別和引用型別的父類,因為Java 對原生型別做了特殊處理。
3.Nothing
Nothing是所有其他型別的子類
Nothing 在Java 中沒有類似的概念,但它填補了存在於Java 型別系統中的空白。Nothing 在編譯器裡的實現相當於以下宣告:
package scala
abstract final class Nothing extends Any
Nothing 實際上繼承了Any。根據型別系統裡的構造規則,Nothing 是所有其他型別的子類,無論是引用型別還是值型別。換句話說,Nothing 繼承了所有一切(everything),這讓它的名字聽起來很奇怪。
Nothing 沒有例項,Nothing 為型別系統提供了兩種功能:
1、用來當做Nil的型別List[Nothing]
package scala.collection.immutable
object Nil extends List[Nothing] with Product with Serializable
Nil表示一個空的list,與list中的元素型別無關,他可以同時表示List[任意型別]的空集合。
2、Nothing 用來表示終止程式,非正常型別的返回值型別
我們可以臨時呼叫??? 方法來定義其他的方法,使得方法定義完整,並通過編譯。但如果呼叫該方法,就會丟擲異常。以下是??? 的定義:
package scala
object Predef {
...
def ??? : Nothing = throw new NotImplementedError
...
}
4.Null與null
Null 對於大多數語言而言是個熟悉的概念。儘管這些語言通常並沒有定義Null 型別,僅僅定義了關鍵字null,用於向引用變數賦值,表示該變數實際上沒有值。Null 在編譯器裡的實現相當於以下宣告:
package scala
abstract final class Null extends AnyRef
該宣告不允許子類派生以及建立例項,但執行時環境提供了一個例項,就是我們最熟悉的、最喜愛、最可惡的null,我們在建立例項時僅僅是想宣告一下變數,暫時不建立例項,這是很容易想到null物件,有了它我們就可以順利編寫程式了,所以null是我們最熟悉、最喜愛的例項,所謂樂極生悲,愛極必反,null也不例外,他也是空指標的萬惡之源,所以他也是最可惡的例項。
Null 被明確定義為AnyRef 的一個子型別,但它也是所有AnyRef 型別的子型別。這是型別系統允許你用null 給任何引用型別賦值的正常做法。另一方面,因為null 不是AnyVal 的子型別,所以不可以用null 給Int 賦值。於是,Scala 的null 與Java 的null 完全相同,因為它必須與Java 的null 共存於JVM。否則,Scala 會破壞null 的概念,引起很多潛在的bug。
5、Nil
Nil是Scala宣告一個空列表的專用型別,它是繼承了List[Nothing] 的物件,它只需要一個例項,因為它沒有攜帶任何“狀態”(元素)。由於List 的型別引數是協變的,對於任意型別A,Nil 是所有List[A] 的子型別。所以,我們不需要分開Nil[A] 例項,一個例項就夠了。
6、Unit
先不多說,原始碼在此
package scala
final abstract class Unit() extends scala.AnyVal {
override def getClass() : _root_.scala.Predef.Class[scala.Unit] = { /* compiled code */ }
}
object Unit extends scala.AnyRef with scala.AnyValCompanion {
def box(x : scala.Unit) : scala.runtime.BoxedUnit = { /* compiled code */ }
def unbox(x : java.lang.Object) : scala.Unit = { /* compiled code */ }
override def toString() : java.lang.String = { /* compiled code */ }
}
Unit是函式和方法的返回值型別,表示沒有返回值。這一點和java的void有點像,但不等同於java的void,因為java的void可以返回null。