除了丹尼尔的回答,请记住这Stream
对于短路评估很有用。例如,假设我有大量的函数来获取String
和返回Option[String]
,并且我想继续执行它们直到其中一个工作:
val stringOps = List(
(s:String) => if (s.length>10) Some(s.length.toString) else None ,
(s:String) => if (s.length==0) Some("empty") else None ,
(s:String) => if (s.indexOf(" ")>=0) Some(s.trim) else None
);
好吧,我当然不想执行整个列表,并且没有任何方便的方法List
可以说,“将它们视为函数并执行它们,直到其中一个返回除None
“之外的其他内容。该怎么办?也许是这样:
def transform(input: String, ops: List[String=>Option[String]]) = {
ops.toStream.map( _(input) ).find(_ isDefined).getOrElse(None)
}
这需要一个列表并将其视为一个Stream
(实际上并不计算任何东西),然后定义一个新的Stream
,它是应用函数的结果(但它也没有计算任何东西),然后搜索第一个已定义——在这里,神奇地,它回顾并意识到它必须应用映射,并从原始列表中获取正确的数据——然后将其Option[Option[String]]
从Option[String]
使用getOrElse
.
这是一个例子:
scala> transform("This is a really long string",stringOps)
res0: Option[String] = Some(28)
scala> transform("",stringOps)
res1: Option[String] = Some(empty)
scala> transform(" hi ",stringOps)
res2: Option[String] = Some(hi)
scala> transform("no-match",stringOps)
res3: Option[String] = None
但它有效吗?如果我们将 aprintln
放入我们的函数中以便我们可以判断它们是否被调用,我们会得到
val stringOps = List(
(s:String) => {println("1"); if (s.length>10) Some(s.length.toString) else None },
(s:String) => {println("2"); if (s.length==0) Some("empty") else None },
(s:String) => {println("3"); if (s.indexOf(" ")>=0) Some(s.trim) else None }
);
// (transform is the same)
scala> transform("This is a really long string",stringOps)
1
res0: Option[String] = Some(28)
scala> transform("no-match",stringOps)
1
2
3
res1: Option[String] = None
(这是 Scala 2.8 的情况;不幸的是,2.7 的实现有时会超调。请注意,随着故障的累积,您确实会积累一长串列表None
,但与您在此处的真实计算相比,这可能是便宜的。)