Scala中的“ 20秒”如何工作?


130

以下内容如何编译:

import scala.concurrent.duration._

val time = 20 seconds

这到底是怎么回事?

Answers:


171

发生了一些事情。

首先,Scala允许在许多方法调用中省略点和括号,因此20 seconds等效于20.seconds()*。

第二,应用“隐式转换”。由于20IntInt没有seconds方法,因为这需要一个隐式转换,编译器搜索Int和返回的东西,确实有seconds方法,通过你的方法调用的范围限制搜索。

您已经将DurationInt导入了您的范围。由于DurationInt是带有Int参数的隐式类,因此其构造函数定义了隐式Int => DurationInt转换。DurationInt有一个seconds方法,因此它满足所有搜索条件。因此,编译器会将您的调用重写为new DurationInt(20).seconds**。

*我的意思是宽松的。20.seconds()实际上是无效的,因为该seconds方法没有参数列表,因此必须在方法调用中省略。

**实际上,这不是很正确,因为它DurationInt是一个值类,因此编译器将尽可能避免包装整数。


83
任何足够先进的技术都无法与魔术区分开。
ripper234

4
幸运的是,大多数IDE都能区分它!隐式转换在Scala中得到了很多使用。如果您只是在阅读文本文件,则可能会造成混淆(“该方法从何而来”),但是在适当的工具支持下,您应该能够找到解决之道,这时Scala可以变得非常有意义且简洁。(例如,new DurationInt(20).seconds()只要知道二十秒的可读性,二十秒的可读性要高得多)
William Billingsley

1
如果您发现自己使用隐式函数,请始终问自己是否有办法在没有他们帮助的情况下实现同一目标。 twitter.github.com/effectivescala/#Types和Generics-Implicits
oluies 2013年

4
实际上,该seconds方法是在没有parens的情况下定义的,因此使用parens进行调用是错误的。
Frank S. Thomas

1
@弗兰克这是一个好点。我并不是要建议您可以用20.seconds()Scala 编写代码,只是建议编译器以这种方式翻译该调用。值得指出的是,在这种情况下,如果相应的方法没有参数列表,则Scala 要求您省略parens。
亚伦·诺夫斯特鲁普

7

那里发生的“魔术”称为“隐式转换”。您正在导入隐式转换,其中一些转换处理Int(和Double)到Duration之间的转换。那就是你要处理的。


1
知道为什么导入import scala.concurrent.duration._可以解析20 seconds但实际上不导入DurationConversionsTrait吗? 编辑:刚意识到他们实际上正在导入的是DurationInt。我猜这是因为您无法导入实际的特征?只有特质的具体实现?
富兰克林'18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.