【发布时间】:2012-05-01 06:31:06
【问题描述】:
是否有一种最佳做法?我一直在阅读 Odersky 等人的 Scala 书。似乎中缀用于很多 Collections API 函数,而 dot 是为程序员定义的函数保留的。
【问题讨论】:
标签: scala methods call infix-notation
是否有一种最佳做法?我一直在阅读 Odersky 等人的 Scala 书。似乎中缀用于很多 Collections API 函数,而 dot 是为程序员定义的函数保留的。
【问题讨论】:
标签: scala methods call infix-notation
我个人对此没有任何硬性规定,但我倾向于仅对符号方法名称使用中缀表示法,对字母数字名称使用点表示法。
中缀表示法使以后修改代码很麻烦。以下是一些示例。
假设你有这行代码:
xs filter { f } map { g }
假设在稍后的某个时间点,您需要在末尾添加一个toList。你这样说:
xs filter { f } map { g } toList
这可能会导致分号推断问题。为避免这些问题,您可以在末尾添加分号,或者换行。在我看来,这两种选择都很丑陋。为了避免所有这些废话,我更喜欢使用xs.filter(f).map(g)。使用这种语法重构总是更容易。
另一个例子:假设我的代码中有以下内容:
if(foo contains bar) { ..
说,我需要否定条件。如果我修改如下:
if(!foo contains bar) { ..
无赖。这被解析为(!foo).contains(bar)。不是我们想要的。
或者假设你需要另外添加一个新的条件,你修改成这样:
if(foo contains bar && cond) { ..
又是一个无赖。这被解析为foo.contains(bar.&&(cond))。又不是我们想要的。
当然,您可以在周围添加一堆括号,但与点符号相比,这会很丑陋且难以阅读/编辑。
现在,我上面所说的所有内容也适用于符号方法名称。但是符号方法在与点语法一起使用时看起来不自然,因此我更喜欢它们的中缀语法。
上述指南的一个例外:内部 DSL。它们通常精心制作,以免在以文档/示例中规定的方式(通常使用中缀符号)编写时导致解析问题。
【讨论】:
(xs filter f map g).toList 仍然比xs.filter(f).map(g).toList) 更清晰、更明显
someExpression => someExpression.newPart 并不明显优于someExpression => (someExpression).newPart 在这两种情况下,您都必须添加.newPart。诚然,您必须在第二种情况下添加括号,但您一开始可能会少很多。稻草人是用“这可能会导致分号推断问题”来证明前一种方法的合理性。解释 - 这是添加后缀调用的症状,而不是原始表达式。
这是个人喜好问题。您决定使用一种风格还是另一种风格应该基于使您的代码最易读的因素。
但请注意,省略点和括号的功能仅限于某些句法结构,因此有时您只需要退回使用它们即可。
【讨论】:
a.op(b) 比a op b 长,但比(a op b) 短。细微差别,但它可以成为“最易读”考虑的一部分。
Scala 官方站点文档中有一个很好的style guide,它描述了中缀表示法优于点表示法的正确用法。
后缀符号:
names.toList
// is the same as
names toList // Unsafe, don't use!
Arity-1:
// right!
names foreach (n => println(n))
names mkString ","
optStr getOrElse "<empty>"
// wrong!
javaList add item
高阶函数:
// wrong!
names.map (_.toUpperCase).filter (_.length > 5)
// right!
names map (_.toUpperCase) filter (_.length > 5)
符号方法/运算符:
// right!
"daniel" + " " + "Spiewak"
// wrong!
"daniel"+" "+"spiewak"
【讨论】:
我发现当我使用 cats 库创建笛卡尔坐标时,使用 map 的中缀表示法效果很好。例如:
(fetchIt(1) |@| fetchIt(2) |@| fetchIt(3)).map(MyCaseClass)
你可以像这样去掉周围的括号:
fetchIt(1) |@| fetchIt(2) |@| fetchIf(3) map MyCaseClass
在我看来,第二个变体读起来更好。我想是口味问题。只是想增加我两美分的价值。
上述方法有效,因为“|@|”中的|在“地图”中具有比m 更高的优先级。阅读 Scala 语言规范的这一部分以了解更多详细信息:
如果一个表达式中有多个中缀操作,那么操作符 具有较高优先级的运算符比具有较低优先级的运算符绑定得更紧密 优先级。
http://scala-lang.org/files/archive/spec/2.12/06-expressions.html#infix-operations
【讨论】: