使用Scala的命令行REPL:
def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}
给
error: type mismatch;
found: Int(2)
required: String
看来你不能定义在REPL重载递归方法。 我认为这是在斯卡拉REPL一个错误,提起它,但它几乎立即与“wontfix关闭:我不认为这可能支持给予解释的语义的方式,因为这两种方法都必须被编译一起。” 他建议把方法在一个封闭的对象。
是否有一个JVM语言实现或斯卡拉专家谁可以解释,为什么? 我可以看到这将是一个问题,如果方法叫对方实例,但在这种情况下?
或者,如果这是太大的问题,你觉得我需要更多的必备知识,是否有人有任何好的链接到有关语言实现的书籍或网站,尤其是在JVM上? (我知道约翰·罗斯的博客,这本书编程语言语......但仅此而已。:)
这个问题是由于这样的事实,解释在多数情况下与一个给定的名称,以取代现有的元素,而不是重载它们。 例如,我经常会通过与实验的东西,往往造成一种称为运行test
:
def test(x: Int) = x + x
过了一会儿,让我们说我运行一个不同的实验,我创建了一个名为另一种方法test
,无关的第一:
def test(ls: List[Int]) = (0 /: ls) { _ + _ }
这并不完全是不现实的场景。 事实上,这恰恰是大多数人是如何使用的解释,往往甚至没有意识到这一点。 如果解释任意决定保留这两个版本test
范围,这可能导致在使用测试混乱语义差异。 例如,我们可以打一个电话来test
,无意中路过的Int
,而不是List[Int]
而不是在世界上最不可能的意外):
test(1 :: Nil) // => 1
test(2) // => 4 (expecting 2)
随着时间的推移,解释器的根范围会得到与各种版本的方式,领域等,我倾向于在同一时间离开我的翻译开了好几天,但如果超载这样的允许,我们将被迫“令人难以置信的混乱冲洗”的解释,每隔一段时间的事情变得过于混乱。
这不是JVM或斯卡拉编译器的限制,这是一个经过深思熟虑的设计决定。 正如错误所提到的,你仍然可以,如果你不是根范围以外的东西内超载。 一类内封闭测试方法似乎是对我最好的解决方案。
% scala28
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def foo(x: Int): Unit = () ; def foo(x: String): Unit = { println(foo(2)) }
foo: (x: String)Unit <and> (x: Int)Unit
foo: (x: String)Unit <and> (x: Int)Unit
scala> foo(5)
scala> foo("abc")
()
如图所示通过即兴的回答,有可能超载。 丹尼尔的有关设计决定的评论是正确的,但是,我认为,不完整的,有点误导。 有没有超载的取缔 (因为它们是可能的),但它们不容易实现的。
设计决策导致这种是:
- 所有以前的定义必须是可用的。
- 只有新输入的代码被编译,而不是重新编译的一切,从来没有入过每一次。
- 它必须能够重新定义(如丹尼尔提到)。
- 它必须能够以限定构件如瓦尔斯和DEFS,不仅类和对象。
问题是...如何实现这些目标? 我们如何处理您的例子吗?
def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}
与第四项开始,A val
或def
只能在内部定义的class
, trait
, object
或package object
。 所以,REPL提出的定义中的对象,这样的( 而不是实际的表现!)
package $line1 { // input line
object $read { // what was read
object $iw { // definitions
def foo(x: Int): Unit = {}
}
// val res1 would be here somewhere if this was an expression
}
}
现在,由于JVM是如何工作的,一旦你定义的其中之一,你不能扩展它们。 你可以,当然,重新编译一切,但我们弃去。 所以,你需要把它放在一个不同的地方:
package $line1 { // input line
object $read { // what was read
object $iw { // definitions
def foo(x: String): Unit = { println(foo(2)) }
}
}
}
这解释了为什么你的例子并不重载:它们是在两个不同的地方定义。 如果你把它们放在同一行,他们全被定义在一起,这将使他们的过载,如图即兴的例子。
至于其他的设计决策,每一个新的包导入定义,并从以前的包“资源”,而进口可能影对方,这使得它能够“重新定义”的东西。