Scala中的空
Scala的有即Any,Scala的无是Null,null,Nil,Nothing,None,Unit.那么这几种空有什么区别呢?
一、Null&null
很多人一辈子都没有走出这个无。Null是一个Trait,你不能创建她它的实例。但是Scala在语言层面上存在一个Null的实例,那就是null。Java中的null意味着引用并没有指向任何对象。但存在一个悖论,一切都是对象,那没有对象是不是也是对象呢?Scala定义了一个类似于对象语义的Null,和一个值语义的null。这样面向对象在空引用的情况下完备了。如果你写了一个带有Null作为参数的对象,那么你传入的参数只能是null,或者指向Null的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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
二、Nil
Nil是一个继承List[Nothing]的对象,我们随后讨论Nothing。它就是一个空的列表,下面是一些使用实例:
1 2 3 4 5 6 7 8 9 10 11 | 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。它并不是一无所有,它是一个容器,一个列表,只是没有存放内容而已。
三、Nothing
Nothing可能比较难理解。Nothing也是一个Trait,它继承自Any,而Any是整个Scala类型系统的根。Nothing是没有实例的,但它时任何对象的子类,他是List的子类,是String的子类,是Int的子类,是任何用户自定义类型的子类。
前面提到Nil是一个空的List[Nothing]。由于Nothing是任何类型的子类,那么Nil就可以当做是一个空的String List,空的Int List,甚至使Any List。Nothing比较适合用来定义基类容器。
1 2 3 4 5 6 7 8 9 10 11 | 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为返回值的函数实际上不可能返回。
四、None
写Java程序的时候,经常会碰到没有有意义的东西可以返回,我们返回null。但返回null有一些问题,调用方必须检查返回值,不然会有NullPointerException的异常。这逼迫我们去check函数的返回值。还有一种解决办法是使用异常,但增加try/catch块,并不是明智的选择。
Scala内置一种解决办法。如果你想返回一个String,但可能有的时候得不到有意义的返回值,我们可以让函数返回Option[String]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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还是慎重。
五、Unit
Unit跟java的void一样,表示函数没有返回值。
1 2 3 4 5 6 7 8 9 | scala> def doThreeTimes(fn: (Int) => Unit) = { | fn(1); fn(2); fn(3); | } doThreeTimes: ((Int) => Unit)Unit scala> doThreeTimes(println) 1 2 3 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构