Scala:协变函数

时间:2014-07-17 23:27:28

标签: scala generics

假设我们在下面有代码段

 trait Foo

  class Bar extends Foo

  def foobar(fn: Option[Set[_ <: Foo] => Unit]) {}

  def main(args: Array[String]) {
  foobar(Option(bar)) //doesnt compile
  }

  def bar(input: Set[Bar]) {}

它进行编译,因为函数1被定义为trait Function1 [-T1, +R] extends AnyRef。我的问题无论如何在Scala中编写一个函数,它接受一个Type T或它的子类型并做一些事情?或者我害怕它不可能

3 个答案:

答案 0 :(得分:3)

您可以将Set中的foobar的类型约束移到函数本身的类型参数上:

trait Foo {

  class Bar extends Foo

  def foobar[A <: Foo](fn: Option[Set[A] => Unit]) {}

  def main(args: Array[String]) {
      foobar(Option(bar _)) //compiles!
  }

  def bar(input: Set[Bar]) {}

}

Scala编译器将从传递给A的参数中推断出类型foobar,同时仍然强制执行类型约束。此外,您需要部分应用barOption传递给它。

答案 1 :(得分:1)

怎么样

trait Foo

class Bar extends Foo

def bar(input: Set[_ <: Foo]) {}

def foobar(fn: Option[Set[_ <: Foo] => Unit]) {}

foobar(Some(bar(_)))  // partially applied

foobar(None)

您现在可以执行类似这样的操作,在某些情况下完全应用foobar()

 val x = Set(new Bar())

 foobar(Some( x => bar(x)))

请注意,必须是x =&gt; bar(x)因为类型是一些函数对象,而不是函数的结果。

答案 2 :(得分:1)

如果你想使用存在而不是Jesse的回答,你可能会有类似的东西:

def foobar(fn: Option[(Set[X] => Unit) forSome { type X <: Foo }]) {}
foobar(Option(bar _))