Scala中的空

   Scala的有即Any,Scala的無是Null,null,Nil,Nothing,None,Unit.那麼這幾種空有什麼區別呢?java

1、Null&nulles6

  不少人一生都沒有走出這個無。Null是一個Trait,你不能建立她它的實例。可是Scala在語言層面上存在一個Null的實例,那就是null。Java中的null意味着引用並無指向任何對象。但存在一個悖論,一切都是對象,那沒有對象是否是也是對象呢?Scala定義了一個相似於對象語義的Null,和一個值語義的null。這樣面向對象在空引用的狀況下完備了。若是你寫了一個帶有Null做爲參數的對象,那麼你傳入的參數只能是null,或者指向Null的引用。less

scala> def tryit(thing: Null): Unit = { println("That worked!"); }
tryit: (Null)Unit
 
scala> tryit("hey")
<console>:6: error: type mismatch;
 found   : java.lang.String("hey")
 required: Null
       tryit("hey")
             ^
 
scala> val someRef: String = null
someRef: String = null
 
scala> tryit(someRef)
<console>:7: error: type mismatch;
 found   : String
 required: Null
       tryit(someRef)
             ^
 
scala> tryit(null)
That worked!
 
scala> val nullRef: Null = null
nullRef: Null = null
 
scala> tryit(nullRef)
That worked!

  第四行咱們試圖傳入一個String,天然不能工做。第14行咱們傳入一個null引用,可是任然不能工做,爲何呢?由於null引用指向的是String類型。它可能在運行時是null,可是在編譯時類型檢查卻不認同,編譯器認爲他是個String函數

2、Nilui

  Nil是一個繼承List[Nothing]的對象,咱們隨後討論Nothing。它就是一個空的列表,下面是一些使用實例:es5

scala> Nil
res4: Nil.type = List()
 
scala> Nil.length
res5: Int = 0
 
scala> Nil + "ABC"
res6: List[java.lang.String] = List(ABC)
 
scala> Nil + Nil
res7: List[object Nil] = List(List())

能夠看出,Nil就是一個能夠封裝任何東西的空容器。它的長度爲0。它並非一無全部,它是一個容器,一個列表,只是沒有存放內容而已。spa

3、Nothingscala

  Nothing可能比較難理解。Nothing也是一個Trait,它繼承自Any,而Any是整個Scala類型系統的根。Nothing是沒有實例的,但它時任何對象的子類,他是List的子類,是String的子類,是Int的子類,是任何用戶自定義類型的子類。對象

 前面提到Nil是一個空的List[Nothing]。因爲Nothing是任何類型的子類,那麼Nil就能夠當作是一個空的String List,空的Int List,甚至使Any List。Nothing比較適合用來定義基類容器。blog

scala> val emptyStringList: List[String] = List[Nothing]()
emptyStringList: List[String] = List()
 
scala> val emptyIntList: List[Int] = List[Nothing]()
emptyIntList: List[Int] = List()
 
scala> val emptyStringList: List[String] = List[Nothing]("abc")
<console>:4: error: type mismatch;
 found   : java.lang.String("abc")
 required: Nothing
       val emptyStringList: List[String] = List[Nothing]("abc")

   第一行,咱們將一個List[Nothing]賦值給一個List[String]。一個Nothing是一個String,所以是正確的。第四行,咱們將一個List[Nothing]賦值給一個List[Int]。一個Nothing是一個Int,所以是正確的。Nothing是任何類型的子類,可是上面的List[Nothing]都不包含任何成員。當咱們建立一個包含一個String的List[Nothing]的List,並把它賦值給List[String],會出現什麼狀況?它會失敗,由於Nothing並非任何類型的父類,而且也不存在Nothing的實例。任何Nothing的容器必然是空的,是Nil。

  另外一種Nothing的用法是做爲不返回函數的返回值。由於Nothing沒有任何實例,而函數的返回值一定是一個值,是一個對象,這樣定義爲Nothing爲返回值的函數實際上不可能返回。

4、None

   寫Java程序的時候,常常會碰到沒有有意義的東西能夠返回,咱們返回null。但返回null有一些問題,調用方必須檢查返回值,否則會有NullPointerException的異常。這逼迫咱們去check函數的返回值。還有一種解決辦法是使用異常,但增長try/catch塊,並非明智的選擇。

  Scala內置一種解決辦法。若是你想返回一個String,但可能有的時候得不到有意義的返回值,咱們可讓函數返回Option[String]。

scala> def getAStringMaybe(num: Int): Option[String] = {
     |   if ( num >= 0 ) Some("A positive number!")
     |   else None // A number less than 0?  Impossible!
     | }
 
getAStringMaybe: (Int)Option[String]
 
scala> def printResult(num: Int) = {
     |   getAStringMaybe(num) match {
     |     case Some(str) => println(str)
     |     case None => println("No string!")
     |   }
     | }
printResult: (Int)Unit
 
scala> printResult(100)
A positive number!
 
scala> printResult(-50)
No string!

   函數getAStringMaybe返回Option[String]。Option是一個抽象類,它有兩個子類:Some和None。所以,初始化一個Option有兩種方法。getAStringMaybe返回的只多是Some[String]或None。Some和None又是Case Class,能夠直接用來作模式匹配,很容易用來處理返回值。

  相似地,Option[T]做爲返回值,意味着調用者可能會收到Some[T]或None。

  其實Option做爲返回值,並無比返回null好多少。代碼裏面充滿了Option和模式匹配的代碼,也不優雅,因此對待Option仍是慎重。

5、Unit

 Unit跟java的void同樣,表示函數沒有返回值。

scala> def doThreeTimes(fn: (Int) => Unit) = {
 | fn(1); fn(2); fn(3);
 | }
 doThreeTimes: ((Int) => Unit)Unit

scala> doThreeTimes(println)
 1
 2
 3
相關文章
相關標籤/搜索