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
相关文章
相关标签/搜索