简体   繁体   中英

Scala: Covariant function

Let say we have code snippet below

 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]) {}

It doest compile because function one is defined as trait Function1 [-T1, +R] extends AnyRef . My Question is there anyway in Scala to write a function that takes a Type T or its subtype and do something? or as I fear its impossible

You can move the type constraints for the Set in foobar out to a type parameter on the function itself:

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]) {}

}

The Scala compiler will infer the type A from the argument passed into foobar , while still enforcing the type constraint. Also, you need to partially apply bar to pass it in an Option like that.

How about

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)

You can now do something like this to fully apply foobar() in the Some case

 val x = Set(new Bar())

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

Note that it has to be x => bar(x) because the type is Some of a function object, not of the function's result.

If you want to use existentials rather than Jesse's answer, you could have something like:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM