6

我的印象是,这

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

是语法糖

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

但在继承方面,我似乎无法将两者混为一谈。整个树必须以短句法或长句法定义;从不两者兼而有之。

例如:

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

所描述的两种方法具有不同的签名。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

第一个是需要两个参数的函数,在单独的参数列表中给出,并返回一个Int. 第二个是一个函数,它接受一个参数并从to返回一个函数。虽然这两个东西在概念上是相似的,但实际上它们是不同的构造,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, 因为它只接受一个参数,所以我们可以只用一个参数调用它。然而,foo1需要两个参数,一个所以我们不能简单地用一个来调用它。但是,您可以使用_语法将其转换为可调用函数。

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 回答