7

これは私のプロジェクトではタイプ セーフの厄介な違反であるため、無効にする方法を探しています。関数が AnyRef (または java.lang.Object) を取る場合、パラメーターの任意の組み合わせで関数を呼び出すことができ、Scala はパラメーターを結合して Tuple オブジェクトにし、関数を呼び出します。

私の場合、関数はタプルを期待しておらず、実行時に失敗します。この状況はコンパイル時にキャッチされると思います。

object WhyTuple {
 def main(args: Array[String]): Unit = {
  fooIt("foo", "bar")
 }
 def fooIt(o: AnyRef) {
  println(o.toString)
 }
}

出力:

(foo,bar)
4

6 に答える 6

7

ここでは Implicit や Predef はまったく機能していません。古き良き時代のコンパイラ マジックです。タイプチェッカーで見つけることができます。現在、仕様で見つけることができません。

十分な動機がある場合は、コンパイラに -X オプションを追加してこれを防ぐことができます。

または、 のスーパータイプを受け入れるアリティ 1 メソッドを作成しないようにすることもできますTupleN

于 2010-05-17T19:32:24.967 に答える
4

このようなものはどうですか:

object Qx2 {
    @deprecated def callingWithATupleProducesAWarning(a: Product) = 2
    def callingWithATupleProducesAWarning(a: Any) = 3
}

タプルには Product トレイトがあるため、タプルを渡す callingWithATupleProducesAWarning を呼び出すと、非推奨の警告が生成されます。

于 2010-05-17T18:32:05.533 に答える
4

編集:私よりも詳しい人々によると、次の答えは実際には間違っています:この答えを参照してください。これを指摘してくれたAaron Novstrupに感謝します。

これは実際には、型システムやコンパイラの癖ではなく、パーサーの癖です。Scala では、引数が 0 または 1 の関数を括弧なしで呼び出すことができますが、複数の引数を持つ関数を呼び出すことはできません。Fred Haslam が言うように、あなたが書いたものは2 つの引数を持つ呼び出しではなく、1 つのタプル値の引数を持つ呼び出しです。ただし、メソッド2 つの引数を取る場合、呼び出しは 2 つの引数の呼び出しなります。コードの意味が解析方法に影響を与えるようです (これはちょっと残念です)。

これについて実際に何ができるかというと、それはトリッキーです。メソッドが実際に 2 つの引数を必要とする場合、この問題は解消されます (つまり、誰かが誤って 1 つまたは 3 つの引数でメソッドを呼び出そうとすると、予想どおりコンパイル エラーが発生します)。そのメソッドに追加するのを先延ばしにしてきた余分なパラメーターがあると思いませんか? :)

于 2010-05-17T17:21:05.413 に答える
1

コンパイルは、丸括弧なしでメソッドを解釈できます。したがって、fooIt の丸括弧はタプルを意味します。あなたの呼び出しは次と同じです:

fooIt( ("foo","bar") )

そうは言っても、Some(AnyRef) や Tuple1(AnyRef) などのラッパーを使用すると、メソッドで呼び出しを除外して値を取得できます。

于 2010-05-17T16:37:26.070 に答える
0

また、コンパイラがシンタックスシュガーを適用できないようにする2パラメータオーバーライドを追加できますか?タイプを適切に不明瞭にすることで、誤検知が発生する可能性が低くなります。例えば:

object WhyTuple {

  ...

  class DummyType

  def fooIt(a: DummyType, b: DummyType) {
    throw new UnsupportedOperationException("Dummy function - should not be called")
  }
}
于 2010-05-18T09:03:37.027 に答える
0

Predef の (x, y) の定義が原因だと思います。"-Yno-predefs" コンパイラ フラグは、他の方法で必要な暗黙的なものを手動でインポートする作業を喜んで行うと仮定すると、何らかの役に立つかもしれません。つまり、どこにでも import scala.Predef._ を追加する必要があるということです。

于 2010-05-17T17:00:55.420 に答える