3

Scala 2.10 の新しい値クラスを試すために、timesRuby が提供するものに沿って 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 ?
}

謎解きが好きな人は、この時点で、上記の結果がどのような出力になるかを自問するかもしれません。期待した出力が生成されませ(上記のコメントで)。

ご覧のように、繰り返し実行されるコードがインデックスを利用するかどうかの 2 つの方法があります。StringBuilder テストに到達するまで、出力は良好に見えます。

111
321
3
java.lang.StringIndexOutOfBoundsException: String index out of range: 3

何が起こっているのか部分的に理解していますが、いくつか質問があります。3 times { s += 'x' }これまでにわかったことは、バージョン Aが呼び出されると思っていたのにtimes、実際にはバージョン B が呼び出されたということです。実際、B を削除 (および 2 番目のテストをコメント アウト) すると、最後のテストで A が呼び出され、完全に機能します。

それはあいまいで、満足するコードブロックとして、または評価後の結果が type を持つ式{ s += 'x' }として解釈できると思います。つまり、StringBuilder 自体を返します。StringBuilder には、特定の文字を取得できるメソッドがあります。コンパイラは後者の解釈を行い、を呼び出す前にブロック内のコードを1 回実行し、結果 (StringBuilder 自体) を に渡します。この時点で StringBuilder には 1 文字しかないため、例外が発生します。=> AnyInt => Anys += 'x'apply( ix:Int )timestimessb.apply(3)

まず、誰かが上記を確認/修正/解明してもらえますか? これを説明する際に使用する適切な用語は何ですか?

第二に、ここで適切な修正は何ですか? 私に起こる唯一のことは、メソッドの1つの名前を変更してあいまいさを避けることです。

4

1 に答える 1

2

正解です。scala のStringbuilderapplyのメソッドは、インデックスの文字を返します。これは、たとえば次のようにキャストできるため、呼び出されます。Stringbuilderf:Int => Any

val s2: (Int => Any) = s += 'x'

これを回避するには、私が考えることができる最善の方法は、匿名関数を明示的に入力することです。

3 times { _:Any => s += 'x' };
于 2013-03-24T12:21:15.707 に答える