如何使这个first-not-null-result函数更优雅/简洁?

Dav*_*lla 3 scala

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 }
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*ung 11

我喜欢雷克斯的答案,但你的问题带来了很多东西,我想扩展它,添加:

  1. 使用Scala的Option/Some/None类来阐明未找到匹配时应返回的内容.你的例子返回null,Rex引发了异常.使用Option会立即清楚我们将返回匹配或"无".
  2. 使用类型参数,因此您不必仅对返回String的函数进行操作.

这是代码:

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 _)))
 }
Run Code Online (Sandbox Code Playgroud)

请注意,当此代码运行时,f2永远不会打印,这表明,由于.view调用,我们在返回匹配之前评估最小函数数.

请注意,此方法的调用者现在必须考虑可能找不到匹配的事实:我们返回Option [T]而不是返回T. 在上面的例子中,它将返回Some("yay").当所有函数都返回None时,返回值将为None.当你将null误认为实际匹配时,不再有NullPointerExceptions!


Rex*_*err 10

def getFirstNN(fs: List[() => String]): String = fs.iterator.map(_()).find(_ ne null).get
Run Code Online (Sandbox Code Playgroud)

  • @jglatre - 这就是使用`iterator`的原因.它将在迭代时进行评估(一旦找到某些东西就停止). (3认同)

Sea*_*ons 5

您可能希望传入getFirstNotNullResult的类型是Stream [String]而不是List [()=> String],并构造如下:

Stream.cons(f1, Stream.cons(f2, Stream.cons(f3, Stream.empty)))
Run Code Online (Sandbox Code Playgroud)

然后getFirstNotNullResult变为:

fs.filter(_ != null).headOption
Run Code Online (Sandbox Code Playgroud)

这也意味着它应该真正返回Option [String],因为你不能保证某些东西是非null的.

正如所建议的那样,我建议Stream的原因是它只根据需要评估Stream的"尾部".因此,如果getFirstNotNullResult发现第一个元素不为null,则第一个Stream.cons调用的第二个参数永远不会被实际执行.