为了尝试 Scala 2.10 中的新值类,我想我会times
按照 Ruby 提供的方式向 Int 添加一个方法,以便轻松重复代码块几次。所以我写了这个:
object Test extends App {
implicit class Int_times( val n:Int ) extends AnyVal {
def times( f: => Any ) { var i = n; while ( i>0 ) { f ; i -= 1 } } // A
def times( f:Int => Any ) { var i = n; while ( i>0 ) { f(i); i -= 1 } } // B
}
3 times print(1) ; println // 111 ?
3 times { print(_) }; println // 321 ?
var x = 0 ; 3 times { x += 1 }; println(x) // 3 ?
var s = new StringBuilder; 3 times { s += 'x' }; println(s) // xxx ?
}
如果您喜欢谜题,此时您可能会问自己上面的输出会产生什么。它不会产生我期望的输出(在上面的评论中)。
如您所见,有两种方法可以使要重复执行的代码可以使用索引或不使用索引。在我们进行 StringBuilder 测试之前,输出看起来不错:
111
321
3
java.lang.StringIndexOutOfBoundsException: String index out of range: 3
我部分了解发生了什么,但我有一些问题。到目前为止我发现的是,虽然我认为这3 times { s += 'x' }
会导致版本 Atimes
被调用,但实际上版本 B 被调用了。实际上,如果我删除 B(并注释掉第二个测试),则会为最后一个测试调用 A 并且可以正常工作。
我猜这{ s += 'x' }
是模棱两可的,可以解释为满足的代码块或评估后结果为 type=> Any
的表达式。也就是说,返回 StringBuilder 本身,而 StringBuilder 有一个方法可以让你获取特定的字符。编译器进行后一种解释并在调用之前执行块中的代码一次,然后将结果(StringBuilder 本身)传递给,然后尝试对其进行索引三次。由于此时 StringBuilder 中只有一个字符,因此会导致异常。Int => Any
s += 'x'
apply( ix:Int )
times
times
sb.apply(3)
那么首先,有人可以确认/纠正/阐明上述内容吗?描述这一点的正确术语是什么?
其次,这里的适当修复是什么?我唯一想到的是通过重命名其中一种方法来避免歧义。