10

ここに2つのREPLセッションがあります(私の質問は異なりますが、この質問に触発されました):

Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def ignore(it: String) = 42
ignore: (it: String)Int

scala> ignore(null.asInstanceOf[Nothing])
res0: Int = 42

と:

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def ignore(it: String) = 42
ignore: (it: String)Int

scala> ignore(null.asInstanceOf[Nothing])
java.lang.NullPointerException
        at .<init>(<console>:9)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

唯一の違いは、最初が Scala 2.9.2 で、2 番目が 2.10.0 であることです。

誰かがこの新しい動作につながる 2.10 の変更点を指摘できますか?

にキャストするNothingのはばかげたことであり、答えは「これはすべて未定義の動作なので、やめてください」かもしれないことは知っていますが、アップグレーダーに潜在的に影響を与える可能性のある種類のように見えます。これを説明する変更の議論に出くわしたことを覚えていません.

4

3 に答える 3

5

Scalaはオプションnullの場合とは異なる扱いをするため、の値でさえ問題があります。使用方法に応じて破損する場合と破損しない場合があるインスタンスは1つではなく、のインスタンスは正確にゼロである必要があります。NonenullNothingNothing

したがって、古い動作がバグ以外の何物であるかはわかりません。リリースノートで修正されたことを指摘する必要がありますが、例外をスローする以外に何か.asInstanceOf[Nothing]をすることに依存することは、タイプの正気とは正反対であり、これ以上何も必要ないと思います。(実際、リリースノートは必要ないと思います。)

于 2012-12-28T20:12:41.403 に答える
3

これは、言語ではなく、コンソールだけの問題のようです。まったく同じメソッドを呼び出すこの小さなアプリケーションを実行すると、scala 2.10 には問題がありません。

object Test extends App {
  override def main(args: Array[String]) {
    println(takesString(null.asInstanceOf[Nothing]))
  }

  def takesString(a: String) = 42
}

上記の例を単純化するには、次のように入力します

null.asInstanceOf[Nothing]

コンソールに同じエラーが表示されます。 タイプの印刷と関係があると思います。

更新:誤って 2.9.2 に対して実行したようです。著者がコメントで指摘しているように、2.10 RC5 のスクリプトとしてはまだ失敗します。

于 2012-12-28T14:54:06.960 に答える
2

「これはすべて未定義の動作なので、(...)」という答えを期待していないことはわかっていますが、「アップグレード者に影響を与える可能性があるもの」を追加するときは、(たとえそれが明らかであっても) 人々ができることを覚えておく必要があります独自の定義により、未定義の動作を持つものの結果に依存したり、期待したりしないでください。

あなたが言及した特定のケースでは、未定義の動作ではないと思います。例外をスローする必要があります。Nothingは のサブクラスでありNull、その逆ではありません。テストせずに最初に期待したのはnull.asInstanceOf[Nothing]ClassCastExceptionではnullなくNothing. ただし、これは特別なインスタンスであることがわかりnullます (Java の場合と同様)。実行してみてください:

scala> "aaa".asInstanceOf[Nothing]
java.lang.ClassCastException: java.lang.String cannot be cast to scala.runtime.N
othing$
        at .<init>(<console>:8)
        at .<clinit>(<console>)

私の推測では、内部的に、実行時にキャストをチェックするためにobj.asInstanceOf[T]呼び出すために発生します。obj.getClass()でメソッドを呼び出すと がnullスローされるためNullPointerException、その例外は の前にスローされClassCastExceptionます。

特定の質問に戻ると、Scala 2.9.2 はその特定のケースを (非常に) 特別な方法で処理しているようです。さらにいくつかのテストを実行します。

scala> ignore(3.asInstanceOf[String])
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stri
ng
        at .<init>(<console>:9)
        at .<clinit>(<console>)
scala> ignore({ println("test"); "aaa" })
test
res6: Int = 42

あなたの場合を除いて、引数が常に評価されていることがわかります。Scala 2.10 は間違いなく最も一貫した動作をしています。ただし、この問題は、Scala 2.10 にアップグレードする開発者には影響しません。obj.asInstanceOf[Nothing]が正しいコードであるケースは見当たりません。

于 2012-12-29T19:08:51.597 に答える