Scala toString:括号还是不括号?

时间:2011-11-14 15:43:14

标签: scala

我希望这个帖子能够覆盖和覆盖toString有或没有空括号的优点/缺点,因为这件事有时让我感到困惑,即使我已经进入Scala很长一段时间。

那么哪一个优于另一个? Scala极客,官员和OCD偏执狂的评论受到高度赞赏。

toString的优点:

  • 乍一看似乎是一个明显而自然的选择;
  • 大多数情况都是微不足道的,只需动态构建字符串,而无需修改内部状态;
  • 另一个常见的情况是将方法调用委托给包装的抽象:

    override def toString = underlying.toString
    

toString()的优点:

  • 绝对不是“类似访问者”的名称(这就是IntelliJ IDEA检查员每隔一段时间就会抱怨的一次);
  • 可能意味着某些CPU或I / O工作(在每次System.arrayCopy次呼叫计数对性能至关重要的情况下);
  • 甚至可能暗示某些可变状态发生变化(考虑一个例子,当第一个toString调用很昂贵时,所以它会在内部缓存,以便将来产生更快的调用。)

那么最佳做法是什么?我还缺少什么吗?

更新:这个问题与每个JVM对象上定义的toString具体相关,所以我希望找到最佳实践,如果它永远存在。

4 个答案:

答案 0 :(得分:22)

这是 Scala编程(第10.3节)必须说的:

  

建议的惯例是每当使用无参数方法   没有参数,方法只能通过访问可变状态   读取包含对象的字段(特别是,它没有   改变可变状态)。此约定支持统一访问   原则,1表示客户端代码不应受到a的影响   决定将属性实现为字段或方法。

这是(非官方的) Scala风格指南(第18页)必须说的:

  

Scala允许省略arity-0方法的括号(no   争论):

reply() 
// is the same as 
reply 
  

然而,这种语法   只应在有问题的方法没有副作用时使用   (纯功能性)。换句话说,省略是可以接受的   调用queue.size时调用括号,但调用println()时不调用括号。   该约定反映了上面给出的方法声明约定。

后者没有提到统一访问原则。

如果您的toString方法可以实现为val,则表示该字段是不可变的。但是,如果您的班级是可变的,toString可能并不会总是产生相同的结果(例如StringBuffer)。所以 Scala编程意味着我们应该在两个不同的情况下使用toString()

1)当其值可变时

2)有副作用时

就我个人而言,我认为忽略其中的第一个是更常见和更一致的。在实践中,toString几乎不会产生副作用。所以(除非它),总是使用toString并忽略统一访问原则(遵循样式指南):保留括号以表示副作用,而不是可变性。

答案 1 :(得分:9)

是的,你遗漏了一些东西:语义。

如果你有一个只返回一个值的方法,你就不应该使用parens。原因是这会使valdef之间的界线模糊,满足Uniform Access Principle。例如。考虑集合的size方法。对于固定大小的向量或数组,这可能只是val,其他集合可能需要计算它。

空的parens的使用应限于执行某种副作用的方法,例如, println(),或增加内部计数器的方法,或重置连接等的方法。

答案 2 :(得分:3)

我建议始终使用toString。关于你对toString()的第三个“专家”:

  

可能意味着一些可变状态发生变化(考虑一个例子,当第一次toString调用很昂贵时,所以它在内部缓存以便将来产生更快的调用。)

首先,toString通常不应该是一项昂贵的操作。但是假设它很昂贵,并且假设您确实选择在内部缓存结果。即使在这种情况下,我也会说使用toString,只要toString结果对于给定的对象状态总是相同的(无论状态如何) toString缓存)。

我不推荐使用toString没有parens的唯一原因是你有一个代码分析器/分析器根据是否存在parens进行假设。在这种情况下,请遵循所述分析器提出的约定。另外,如果您的toString那么复杂,请考虑将其重命名为其他内容,例如expensiveToString。非正式地预期toString在大多数情况下是一个简单明了的函数。

答案 3 :(得分:2)

在这个答案中没有多少论证,但仅GenTraversableOnce声明了以下没有括号的defs:

toArray
toBuffer
toIndexedSeq
toIterable
toIterator
toList
toMap
toSeq
toSet
toStream
toTraversable