如何根据类型参数的类型参数编写具有多态返回类型的函数?

Dae*_*yth 9 polymorphism scala type-inference

我有一些像这样的代码:

sealed trait Foo[A] {
  def value: A
}
case class StringFoo(value: String) extends Foo[String]
case class IntFoo(value: Int) extends Foo[Int]
Run Code Online (Sandbox Code Playgroud)

我想要一个可以使用A给定子类型参数的类型的函数.

// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何以dostuff一种有效的方式声明.我能弄清楚的最接近的事情是

def dostuff[B <: Foo[A]](p: Param): A
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为A在该位置未定义.我可以做点什么

def dostuff[A, B <: Foo[A]](p: Param): A
Run Code Online (Sandbox Code Playgroud)

但后来我必须调用它,就像dostuff[String, StringFoo](param)它非常难看.

看起来编译器应该具有移动A到返回类型所需的所有信息,如何在标准scala或库中进行此工作.如果这会影响答案,我现在在scala 2.10上.如果有可能的话,我会接受2.11的解决方案,但在2.10中是不可能的

gzm*_*zm0 7

另一种选择是使用类型成员:

sealed trait Foo {
  type Value
  def value: Value
}

case class StringFoo(value: String) extends Foo { type Value = String }
case class IntFoo(value: Int) extends Foo { type Value = Int }

def dostuff[B <: Foo](p: Any): B#Value = ???

// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
Run Code Online (Sandbox Code Playgroud)

请注意,这两个解决方案主要解决Scala中的语法限制,您无法修复列表的一个类型参数并让编译器推断另一个.


Ben*_*ich 6

您可能知道,如果您有一个类型的参数Foo[A],那么您可以使方法通用A:

def dostuff[A](p: Foo[A]): A = ???
Run Code Online (Sandbox Code Playgroud)

因为这可能并非总是如此,我们可以尝试使用能表达之间的关系的隐含参数AB.因为我们不仅可以将一些通用参数应用于方法调用(泛型参数推断是全部或全部),我们必须将其拆分为2个调用.这是一个选项:

case class Stuff[B <: Foo[_]]() {
    def get[A](p: Param)(implicit ev: B => Foo[A]): A = ???
}
Run Code Online (Sandbox Code Playgroud)

您可以检查REPL中的类型:

:t Stuff[IntFoo].get(new Param) //Int
:t Stuff[StringFoo].get(new Param) //String
Run Code Online (Sandbox Code Playgroud)

沿着相同的行,但使用匿名类的另一个选项是:

def stuff[B <: Foo[_]] = new { 
    def apply[A](p: Param)(implicit ev: B <:< Foo[A]): A = ??? 
}

:t stuff[IntFoo](new Param) //Int
Run Code Online (Sandbox Code Playgroud)

在这里,我已经使用applyget,所以你可以更自然地应用这个方法.另外,正如您的评论中所建议的那样,我<:<在证据类型中使用过.对于那些希望了解有关此类广义类型约束的更多信息的人,可以在此处阅读更多内容.

您也可以考虑使用抽象类型成员而不是通用参数.在努力进行泛型类推理时,这通常会提供一种优雅的解决方案.您可以在此处阅读有关抽象类型成员及其与泛型的关系的更多信息.