当匹配的模式为Nil并且我们要返回Nil时,什么是适当的返回值?

问题描述:

我是Scala和函数式编程的新手。所以这是我的疑问。我们应该返回Nil还是数据类型本身呢?例如,当匹配的模式为Nil并且我们要返回Nil时,什么是适当的返回值?

def drop[A](l: List[A], n: Int): List[A] = { 
    if (n <= 0) l 
    else l match { 
     case Nil => Nil 
     case Cons(_, t) => drop(t, n - 1) 
    } 
} 

这是丢弃来自单链表第一n头元件的功能。在这里,对于第一种情况,我应该返回Nil(也许是一种好的做法),或者我应该返回l(因为那么我们不需要构造Nil对象)?

Nil对象只有一个单例实例。当你写Nil你不会每次创建一个新的,你只使用唯一存在的。

通常最好写Nil,因为它更具可读性。至少这是我一直在阅读和写作的内容。

+0

谢谢!这就说得通了。 – aa8y 2015-02-24 20:50:10

由于只有一个NIL实例,所以它并不重要,因为它是实际相同的对象。


现在真正的问题是:什么更可读?

  • 如果你想清楚,当你Nil,则返回Nil,然后写Nil => Nil
  • 如果它似乎更符合逻辑返回l,即使它实际上是Nil,然后写Nil => l

恕我直言,你的情况,Nil => Nil对我来说比较清楚。

+1

你可以举个例子来说明返回值是否为'Nil'但写入'l'使得代码更具可读性吗?我已经看到了我有一个累加器初始化为'Nil'的实例,它被返回是因为它可能会或可能不会累积更多的值。但我还没有看到你提到的情况。 – aa8y 2015-02-24 21:00:28

如果Nil => Nil真的是你的主要逻辑流程中得罪了你的感情,你可能会考虑充实,我的图书馆式的隐含类的新方法中隐藏:

implicit class ListWithIfNonEmpty[A](list: List[A]) { 
    /** 
    * Replaces a list with a new one in the case that it is 
    * not empty. newList is probably a conversion of the original 
    * list, but the original list is available in the caller's 
    * scope, so no need to pass it as a parameter. 
    */ 
    def ifNonEmpty[B](newList: => List[B]): List[B] = list match { 
    case Nil => Nil 
    case _ => newList 
    } 
} 

然后你drop方法变得稍微更清洁:

def drop[A](l: List[A], n: Int): List[A] = l.ifNonEmpty { 
    if (n <= 0) l else drop(l.tail, n - 1) 
} 

也许这个新方法的名字不那么尴尬。在这种情况下,这种事情对于您的主逻辑流程来说只是一个巨大的胜利,在这种情况下,方法名称使得您要实现的语义非常明显。但你得到了漂移。