17.2 基础类型
不仅可以在 Scala 中使用 Java 的任何类型,
而且同时也可以享受到由 Scala 提供的一些原生类型。
Any
类型
scala 的 Any
类型的所有超类型.
Any
类型可以作为任意类型对象的一个通用引用。
Any
是一个抽象类,定义了如下方 法:
!=()
##()
==()
asInstanceOf
equals()
hashCode()
isInstanceOf
toString()
getClass()
AnyVal
和AnyRef
Any
类型的直接后裔是 AnyVal
和 AnyRef
类型。
AnyVal
是 Scala 中所有值类型(如 Int、Double
等)的基础类型,并映射到了 Java 中的原始类型,
而 AnyRef
是所有引用类型的基础类型。
尽管 AnyVal
没有什么额外的方法,但是 AnyRef
包含了 Java 的 Object
的方法,如 notify()、wait()、finalize()
等。
Any
类型位于类型层次结构的最顶层,而最底层的类型是 Nothing
。
Nothin
类型
在 Scala 中,Nothing
是一切类型的子类型。
我们很容易明白我们为何需要 Any
类型,但是 Nothing
类型在一开始看起来相当奇怪,特别是因为它代表了任何类型的子类型。
Nothing
类型在 Scala 的类型验证机制的支持上意义重大。
Scala 的类型推断尽可能地 确定表达式和方法的类型。如果推断出的类型太过宽泛,则不利于类型验证。
同时,我们确实也希望可以推断这样的表达式或函数的类型,例如: 在分支中, 其一个分支可以返回,如 Int
类型的结果, 而另一个分支抛出异常.
def someOp(number: Int) = {
if (number < 10)
number * 2
else
throw new RuntimeException("invalid argument")
}
在前面这种情况下,将该函数的返回类型推断为 Any
类型则太宽泛了,而且也没有什么用, 而将返回类型推断为 Int
则更为有用。
我们可以很容易地看出该算术表达式的计算结果类型为 Int
。
此外,也必须要推断抛出异常的分支的结果类型,在这种情况下,需要为其返回一个 Int
类型或者 Int
类型的子类型,以便使其和推断的返回类型兼容。
但是,throw
语句的结果类型不能被推断为 Int
类型而被任意处理, 因为在任何地方都可能会引发异常。 Nothing
类型这时候就派上用场了—--通过作为所有类型的子类型,它使类型推断过程得以顺利进行。
因为Nothing
是所有类型的子类型,所以它可以替代任何东西。
Nothing
是抽象的,因此在运行时永远都不会得到一个真正的 Nothing
实例。
Option
类型
Java 的空指针异常是所有程序员的梦魇. Java 之父曾经也说过 null
的设计师他的一个错误.
在 Joshua Bloch 的 Effective Java[Blo08] 一书中有这样的合理建议: 返回空集合,而不是 null 引用。
如果遵循这个建议,我们就不必忍受 NullPointerException
了。
即使结果 集合为空,迭代也会变得很容易。在使用集合的时候,这是很好的建议,但是在使用其他返回类型时,我们也需要类似的内容。
例如,在执行模式匹配时,匹配的结果可能是对象、列表、元组等,也可能不存在。从两方面来说,悄无声息地返回一个 null 是有问题的。
- 首先,可能没有结果值这个事实并没有被明确地(通过类型)表示出来。
- 其次,没有办法强制要求函数的调用者来检查是不存在 还是
null
。
Scala 进一步指定了可能的不存在性。使用 Scala 的 Option[T]
,可以进行有意图的编程,并指定打算不返回结果。
Scala 以类型安全的方式实现了这一点,因此可以在编译时强制 进行检查。
Option
有两个子类:Some
和None
当返回类型是Option
的时候, 其实就是在告诉调用者: 哥们, 返回的值中有可能有null
你要小心了.
object Test {
def commentOnPractice(input: String) = { // 而不是返回 null
if (input == "test")
Some("good")
else
None
}
def main(args: Array[String]): Unit = {
for (input <- Set("test", "hack")) {
val comment = commentOnPractice(input)
// 如果返回的是None, 则把参数返回
val commentDisplay = comment.getOrElse("Found no comments")
println(s"input: $input comment: $commentDisplay")
}
}
}
Either
类型
当一个函数调用的结果可能存在也可能不存在时,Option
类型很有用。
有时候,你可能希望从一个函数中返回两种不同类型的值之一。
这个时候,Scala
的 Either
类型就派上用场了。
Either
本身是个抽象类, 他有两个直接的实现子类: Left
和Right
左值(Left
)(通常被认为是错误)和右值(Right
)(通常被认为是正确的或者符合预期的值)。
object Test {
def compute(input: Int): Either[String, Double] = {
if (input > 0)
Right(math.sqrt(input))
else
Left("Error computing, invalid input")
}
def displayResult(result: Either[String, Double]): Unit = {
result match {
case Left(value) => println(s"result = $value")
case Right(error) => println(s"error = $error")
}
}
def main(args: Array[String]): Unit = {
// 使用模式匹配来取出其中的值
displayResult(compute(10))
displayResult(compute(-10))
}
}