6

という印象を受けました

// short syntax
def foo(bar: Bar)(baz: Baz): Quux

このための構文シュガーでした

// long syntax
def foo(bar: Bar): (Baz) => Quux

しかし、継承に関しては、2つを混在させることはできないようです。ツリー全体を短い構文または長い構文で定義する必要があります。決して両方ではありません。

例えば:

case class Context
case class Work

trait ContextualWorker {
  def workWithContext(ctxt: Context)(work: Work): Traversable[Work]
}

class ShortConcreteWorker extends ContextualWorker {
  override def workWithContext(ctxt: Context)(work: Work) = Nil
}

class LongConcreteWorker extends ContextualWorker {
  // error on next line: method workWithContext overrides nothing    <-------------
 override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = {
    val setupCode = 1
    { work => Nil }
  }
}

長い構文を使用するように特性を変更すると、ShortConcreteWorker はコンパイルされません。

これらが交換可能/継承可能でない理由はありますか? どうやってそれを回避しましたか?

現在、最も柔軟なアプローチは、ツリーを長い構文で定義することであり、おそらく次のように ShortConcreteWorker の実装クラスに委譲することです。

case class Context
case class Work

trait ContextualWorker {
  def workWithContext(ctxt: Context): (Work) => Traversable[Work]
}

class ShortConcreteWorker extends ContextualWorker {
  override def workWithContext(ctxt: Context) = workWithContextImpl(ctxt)_ 
  private def workWithContextImpl(ctxt: Context)(work: Work) = Nil
}

class LongConcreteWorker extends ContextualWorker {
  override def workWithContext(ctxt: Context): (Work) => Traversable[Work] = {
    val setupCode = 1
    { work => Nil }
  }
}
4

1 に答える 1

5

説明されている2つのメソッドは、非常に単純に異なるシグネチャを持っています。REPLはこれを確認します:

scala> def foo1(a: Int)(b: Int): Int = a + b
foo1: (a: Int)(b: Int)Int

scala> def foo2(a: Int): (Int => Int) = (b: Int) => a + b
foo2: (a: Int)Int => Int

1つ目は、別々の引数リストで指定された2つの引数を必要とし、を返す関数ですInt2つ目は、 1つの引数を取り、からへの関数を返す関数です。これらの2つは概念的には似ていますが、実際には異なる構成であり、Scalaはそれらをそのように扱います。IntInt

これは、複数の引数リストを持つ関数に限定されません。ここでも同じように機能します。

scala> def foo3(a: Int): Int = a + 1
foo3: (a: Int)Int

scala> def foo4: (Int => Int) = (a: Int) => a + 1
foo4: Int => Int

使用法にもさまざまな影響があることに注意してください。を使用foo2すると、1つの引数しか受け入れないため、1つの引数だけで呼び出すことができます。ただし、foo12つの引数が必要なため、1つで単純に呼び出すことはできません。ただし、構文を使用して呼び出し可能な関数に変換することはできます_

foo2(2)    // Int => Int = <function1>
foo1(2)    // error: missing arguments for method foo1
foo1(2) _  // Int => Int = <function1>

それであなたの質問に直接答えるために:それらが交換可能でない理由はそれらが同じではないからです。それらが同じであれば、同じように呼び出すことができます。拡張時に署名を変更できるとしたら、Scalaはどの呼び出し構文を許可するかをどのように知るのでしょうか?これを「回避」する方法は、単に署名の一貫性を保つことです。

于 2012-04-30T21:39:21.420 に答える