什么时候可以省略(省略)括号,圆点,大括号,=(函数)等的精确规则?
例如,
(service.findAllPresentations.get.first.votes.size) must be equalTo(2).
-
service
是我的对象 -
def findAllPresentations: Option[List[Presentation]]
-
votes
返回List[Vote]
-
必须是并且都是规格的功能
为什么我不能去:
(service findAllPresentations get first votes size) must be equalTo(2)
?
编译器错误是:
“Option [List [com.sharca.Presentation]]类型的RestServicesSpecTest.this.service.findAllPresentations不接受参数”
为什么它认为我试图传递一个参数?为什么我必须为每个方法调用使用点?
为什么 (service.findAllPresentations get first votes size)
必须等于(2)导致:
“未找到: Value 第一”
然而, (service.findAllPresentations.get.first.votes.size)
的"must be equalTo 2"必须等于2,也就是说,方法链接工作正常? - 对象链链链接 .
我查看了Scala的书籍和网站,无法找到全面的解释 .
实际上,正如Rob H在Stack Overflow问题Which characters can I omit in Scala?中解释的那样,省略'.'的唯一有效用例是"operand operator operand"样式操作,而不是方法链接?
6 回答
你似乎偶然发现了答案 . 无论如何,我会尽力说清楚 .
使用前缀,中缀和后缀表示法时可省略点 - 所谓的运算符表示法 . 使用运算符表示法时,只有这样,如果传递给方法的参数少于两个,则可以省略括号 .
现在,运算符表示法是方法调用的表示法,这意味着它不能在没有被调用的对象的情况下使用 .
我将简要介绍一下这些符号 .
Prefix:
只有
~
,!
,+
和-
可用于前缀表示法 . 这是您在编写!flag
或val liability = -debt
时使用的符号 .Infix:
这是方法出现在对象和它的参数之间的符号 . 算术运算符都适合这里 .
Postfix (also suffix):
当方法跟随对象 and receives no parameters 时使用该表示法 . 例如,您可以编写
list tail
,这是后缀表示法 .只要没有方法,就可以毫无问题地链接中缀符号 . 例如,我喜欢使用以下样式:
这与以下内容相同:
现在,为什么我在这里使用括号,如果filter和map只使用一个参数?这是因为我将匿名函数传递给他们 . 我不能将匿名函数定义与中缀样式混合,因为我需要一个边界来结束我的匿名函数 . 此外,匿名函数的参数定义可能被解释为中缀方法的最后一个参数 .
您可以使用具有多个参数的中缀:
使用中缀表示法很难使用Curried函数 . 折叠功能就是一个明显的例子:
您需要在中缀调用之外使用括号 . 我不确定这里的确切规则 .
现在,我们来谈谈postfix . Postfix可能很难使用,因为除了表达式的结尾之外,它永远不会被使用 . 例如,您无法执行以下操作:
因为尾部没有出现在表达式的末尾 . 你不能这样做:
您可以使用括号来标记表达式的结尾来使用中缀表示法:
请注意,不建议使用后缀表示法,因为it may be unsafe .
我希望这已经消除了所有的疑虑 . 如果没有,只需发表评论,我就会看到我可以做些什么来改进它 .
class 定义:
val
或var
可以从类参数中省略,这将使参数变为私有 .添加var或val将导致它是公共的(即生成方法访问器和更改器) .
如果该类没有正文,则可以省略
{}
,即类实例化:
如果可以由编译器推断出通用参数,则可以省略它们 . 但请注意,如果您的类型不匹配,则始终输入type参数以使其匹配 . 因此,如果没有指定类型,您可能无法得到您所期望的 - 也就是说,给定
这将给你一个类型错误(找到Int,期望String)
虽然这很好用:
因为类型参数T被推断为两者中最不常见的超类型 - 任何 .
函数定义:
如果函数返回Unit(无),则可以删除
=
.{}
如果是函数体可以删除function是单个语句,但仅当语句返回一个值(你需要=
符号)时,即但这不起作用:
如果可以推断出函数的返回类型(递归方法必须指定其返回类型),则可以省略该函数的返回类型 .
如果函数不带任何参数,则可以删除
()
,即按照惯例,它被保留用于没有副作用的方法 - 稍后会更多 .
()
在定义pass by name参数时实际上并没有被删除,但它实际上是一个语义上不同的表示法,即表示myOp采用pass-by-name参数,这会产生一个String(也就是说,它可以是一个返回字符串的代码块),而不是函数参数,
其中说
myOp
采用一个零参数的函数并返回一个String .(请注意,按名称传递的参数会被编译成函数;它只会使语法更好 . )
如果函数只接受一个参数,则可以在函数参数定义中删除
()
,例如:但是如果它需要多个参数,则必须包含():
声明:
可以删除
.
以使用运算符表示法,该表示法只能用于中缀运算符(带参数的方法的运算符) . 有关更多信息,请参见Daniel's answer ..
也可以删除后缀函数列表尾部可以为后缀运算符list.tail删除
()
()
不能与定义为的方法一起使用:因为这种符号是按照惯例为没有副作用的方法保留的,比如List#tail(也就是说,没有副作用的函数的调用意味着函数没有可观察到的效果,除了它的返回值) .
传递单个参数时,可以删除
()
以获取运算符表示法()
可能需要使用不在语句末尾的后缀运算符()
可能需要指定嵌套语句,匿名函数的结尾或带有多个参数的运算符当调用带函数的函数时,不能省略内部函数定义中的(),例如:
调用带有by-name参数的函数时,不能将参数指定为无参数的匿名函数 . 例如,给定:
您必须将其称为:
要么
但不是:
IMO,过度使用丢弃的返回类型可能对重用代码有害 . 只需查看规范,就可以了解由于代码中缺少显式信息而导致可读性降低的好例子 . 实际计算出变量类型的间接层次数可以是坚果 . 希望更好的工具可以避免这个问题,并保持我们的代码简洁 .
(好的,为了编写一个更完整,更简洁的答案(如果我错过了任何内容,或者得到了错误/不准确请注释),我已经添加到答案的开头 . 请注意这不是一种语言规范,所以我不是想让它在学术上完全正确 - 更像是参考卡 . )
一系列报价,可以深入了解各种情况......
就个人而言,我认为规范中还有更多内容 . 我肯定一定有,我只是不寻找合适的词......
然而,有几个来源,我已经收集了它们,但没有真正完整/全面/可理解的/向我解释上述问题......:
来自chapter 2, "Type Less, Do More", of Programming Scala:
来自chapter 1, "Zero to Sixty: Introducing Scala", of Programming Scala:
来自博客文章Scala Syntax Primer:
从语言规范:
来自Scala for Java Refugees Part 6: Getting Over Java:
Which characters can I omit in Scala?
但令我困惑的是这句话:
因为据我所见,有一个对象接收电话......
实际上,在二读时,也许这是关键:
正如博客文章中所述:http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 .
所以也许这实际上是一个非常严格的"syntax sugar",它只适用于你在一个对象上有效调用方法的地方,它接受一个参数 . 例如
没有别的 .
这可以解释我在问题中的例子 .
但正如我所说的,如果有人能指出确切地指出了语言规范的哪个位置,那将非常感激 .
好吧,一些好人(来自#scala的paulp_)指出了语言规范中的这个信息是:
嗯 - 对我而言,它与我所看到的不相符,或者我只是不理解它;)
没有 . 您可能会收到有关该功能是否有副作用的建议 . 这是假的 . 更正是在Scala允许的合理范围内不使用副作用 . 在某种程度上它不能,那么所有的赌注都是关闭的 . All 投注 . 使用括号是集合"all"的一个元素,并且是多余的 . 所有投注结束后,它不提供任何 Value .
这个建议本质上是一个失败的尝试(不要混淆:没有其他效果系统有用) .
尽量不要副作用 . 在那之后,接受所有赌注都已关闭 . 隐藏在效果系统的事实上的句法符号背后可以而且确实只会造成伤害 .
我发现遵循这个经验法则更容易:在表达式中,空格在方法和参数之间交替 . 在您的示例中,
(service.findAllPresentations.get.first.votes.size) must be equalTo(2)
解析为(service.findAllPresentations.get.first.votes.size).must(be)(equalTo(2))
. 请注意,2周围的括号具有比空格更高的关联性 . 点也具有更高的关联性,因此(service.findAllPresentations.get.first.votes.size) must be.equalTo(2)
将解析为(service.findAllPresentations.get.first.votes.size).must(be.equalTo(2))
.service findAllPresentations get first votes size must be equalTo 2
解析为service.findAllPresentations(get).first(votes).size(must).be(equalTo).2
.