getFirstNotNullResult执行函数列表,直到其中一个函数返回非null值。 如何更优雅/简洁地实现getNotNullFirstResult?
object A {
def main(args: Array[String]) {
println(test());
}
def test(): String = {
getFirstNotNullResult(f1 _ :: f2 _ :: f3 _ :: Nil);
}
def getFirstNotNullResult(fs: List[() => String]): String = {
fs match {
case head::tail =>
val v = head();
if (v != null) return v;
return getFirstNotNullResult(tail);
case Nil => null
}
}
// these would be some complex and slow functions; we only want to execute them if necessary; that is, if f1() returns not null, we don't want to execute f2 nor f3.
def f1(): String = { null }
def f2(): String = { "hello" }
def f3(): String = { null }
}
答案 0 :(得分:11)
我喜欢雷克斯的答案,但你的问题带来了很多东西,我想扩展它,添加:
以下是代码:
object A extends App {
def getFirstNNWithOption[T](fs: List[() => Option[T]]): Option[T] = fs
.view //allows us to evaluate your functions lazily: only evaluate as many as it takes to find a match
.flatMap(_()) //invoke the function, discarding results that return None
.headOption // take the first element from the view - returns None if empty
def f1 = { println("f1"); None }
def f2 = Some("yay!")
def f3 = { println("f2"); None }
println(getFirstNNWithOption(List(f1 _, f2 _, f3 _)))
}
请注意,当此代码运行时,f2永远不会打印,这表明,由于.view调用,我们会在返回匹配项之前评估最小函数数。
请注意,此方法的调用者现在必须考虑可能找不到匹配的事实:我们返回Option [T]而不是返回T.在上面的例子中,它将返回Some(“yay”)。当所有函数都返回None时,返回值将为None。当你将null误认为实际匹配时,不再有NullPointerExceptions!
答案 1 :(得分:9)
def getFirstNN(fs: List[() => String]): String = fs.iterator.map(_()).find(_ ne null).get
答案 2 :(得分:5)
您可能希望传入getFirstNotNullResult的类型为Stream [String]而不是List [()=>字符串]并构造如下:
Stream.cons(f1, Stream.cons(f2, Stream.cons(f3, Stream.empty)))
然后getFirstNotNullResult变为:
fs.filter(_ != null).headOption
这也意味着它应该真正返回Option [String],因为你不能保证某些东西是非空的。
正如所建议的那样,我建议Stream的原因是它只评估"尾部"按需流。因此,如果getFirstNotNullResult发现第一个元素不为null,那么第一个Stream.cons调用的第二个参数永远不会被实际执行。