大多数语言都有一个特殊的关键字或者对象来表示一个对象引用的是“无”,在Java,它是null。在java中,null是一个关键字,不是一个对象,所以对它调用任何方法都是非法的。但是这对语言设计者来说是一件令人疑惑的选择。为什么要在程序员希望返回一个对象的时候返回一个关键字呢?
为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,Scala鼓励你在变量和函数返回值可能不会引用任何值的时候使用Option类型。在没有值的时候,使用None,这是Option的一个子类。如果有值可以引用,就会使用Some来包含这个值。Some也是Option的一个子类。
None被声明为一个对象,而不是一个类。因为我们只需要他的一个实例。这样,它多少有点像null关键字,但它却是一个实实在在的,有方法的对象。
1.Option类型的值通常作为Scala集合类型(List、Map等)操作的返回类型。比如Map的get方法;
object Test {
def main(args: Array[String]): Unit = {
//Option类型的值通常作为Scala集合类型(List,Map等)操作的返回类型。比如Map的get方法:
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("France")
println(maybeString)
val maybeString1 = test.get("hanguo")
println(maybeString1)
}
}
结果:
2. Option有两个子类别,Some和None。当程序回传Some的时候,代表这个函式成功地给了你一个String,而你可以透过get()函数拿到那个String,如果程序返回的是None,则代表没有字符串可以给你。
在返回None,也就是没有String给你的时候,如果你还硬要调用get()来取得 String 的话,Scala一样是会抛出一个NoSuchElementException异常给你的
object Test {
def main(args: Array[String]): Unit = {
// //Option类型的值通常作为Scala集合类型(List,Map等)操作的返回类型。比如Map的get方法:
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("France")
println(maybeString)
val maybeString1: Option[String] = test.get("hanguo")
println(maybeString1)
val value: String = maybeString.get
println(value)
val value1 = maybeString1.get
println(value1)
}
}
运行结果:
3.我们也可以选用另一个方法,getOrElse。这个方法在这个Option是Some的实例时返回对应的值,而在是None的实例时返回传入的参数。换句话说,传入getOrElse的参数实际上是默认返回值。
object Test {
def main(args: Array[String]): Unit = {
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("France")
val str: String = maybeString.getOrElse("空值")
println(str)
val maybeString1: Option[String] = test.get("hanguo")
val str1: String = maybeString1.getOrElse("空值")
println(str1)
}
}
运行结果:
4.通过模式匹配分离可选值,如果匹配的值是Some的话,将Some里的值抽出赋给x变量:
object Test {
def main(args: Array[String]): Unit = {
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("France")
val unit: Any = showCapital(maybeString)
println(unit)
val maybeString1: Option[String] = test.get("hanguo")
val unit1: Any = showCapital(maybeString1)
println(unit1)
}
def showCapital(x:Option[String])=x match {
case Some(s)=>s
case None=>"?"
}
}
运行结果:
在Scala里Option[T]实际上是一个容器,就像数组或是List一样,你可以把他看成是一个可能有零到一个元素的List。
当你的Option里面有东西的时候,这个List的长度是1(也就是 Some),而当你的Option里没有东西的时候,它的长度是0(也就是 None)。
for循环
如果我们把Option当成一般的List来用,并且用一个for循环来走访这个Option的时候,如果Option是None,那这个for循环里的程序代码自然不会执行,于是我们就达到了不用检查Option是否为None这件事。
代码里我们用 showContentLen 方法测试:
object Test {
def main(args: Array[String]): Unit = {
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("Fance")
val unit: Any = showCapital(maybeString)
showContentLen(maybeString)
println(unit)
val maybeString1: Option[String] = test.get("hanguo")
val unit1: Any = showCapital(maybeString1)
showContentLen(maybeString1)
println(unit1)
}
def showCapital(x:Option[String])=x match {
case Some(s)=>s
case None=>"?"
}
def showContentLen(x:Option[String])={
for (c<-x){
println("长度为:"+c.length)
}
}
}
运行结果:
5.map操作
在函数式编程中有一个核心的概念之一是转换,所以大部份支持函数式编程语言,都支持一种叫map()的动作,这个动作是可以帮你把某个容器的内容,套上一些动作之后,变成另一个新的容器。
现在我们考虑如何用Option的map方法实现length: xxx的输出形式:
object Test {
def main(args: Array[String]): Unit = {
val test: Map[String, String] = Map("France" -> "Paris", "Japan" -> "Tokyo", "China" -> "Beijing")
val maybeString: Option[String] = test.get("France")
val maybeString2: Option[String] = maybeString.map(_.length).map("length:"+_)
println(maybeString2)
maybeString2.foreach(print)
}
}
运行结果: