我有以下内容:
class Goo
trait Bar[D] {
def toD : D
}
class Moo extends Bar[Goo] {
def toD : Goo = new Goo
}
object Foo {
import scala.collection.JavaConversions._
import java.util
implicit def scalaSetToJavaSet[D](bars: Set[Bar[D]]) : util.Set[D] = bars.map(_.toD)
}
trait Zoo {
import java.util
import Foo._
var javaSet : util.Set[Goo] = Set(new Moo) //compile error
var explicitJavaSet: util.Set[Goo] = scalaSetToJavaSet(Set(new Moo)) //works!!!
}
当我尝试编译此代码时出现错误:
"error: type mismatch;
found : scala.collection.immutable.Set[Moo]
required: java.util.Set[Goo]
var javaSet : util.Set[Goo] = ***Set(new Moo)***"
显式定义编译。为什么隐式转换不起作用?
答案 0 :(得分:7)
这确实很棘手。基本上你的想法是正确的。您可以定义导入的转换方法scalaSetToJavaSet
。问题来自于(Scala)Set[A]
在其类型参数A
中不变的事实。这意味着Set[Moo]
不是Set[Bar[_]]
的子类型。
为了解决这个问题,你需要告诉隐式转换,set元素可以是bar的子类型:
implicit def scalaSetToJavaSet[D, B <: Bar[D]](bars: Set[B]): java.util.Set[D] =
bars.map(_.toD)
val javaSet: java.util.Set[Goo] = scala.Set(new Moo) // ok
您现在可以这样理解:给定类型D
和类型参数为Bar
的某些子类型D
,进行转换。此方法现在称为scalaSetToJavaSet[Goo, Moo]
(而不是scalaSetToJavaSet[Goo, Bar[Goo]]
)。
正如其他人所指出的那样,使用JavaConversions
的现成转换更容易,而不是自己编写。
答案 1 :(得分:1)
首先隐式函数scalaSetToJavaSet
不起作用,因为它期望Set[Bar[D]]
并且您正在传递Set[Moo]
。这是因为Set的类型参数是不变的而不是共变体(如果是List,它会起作用)。
所以简短的回答是
import scala.collection.JavaConversions._
var javaSet : util.Set[Moo] = Set(new Moo)
或者您可以将声明更改为:
implicit def scalaSetToJavaSet[D,T <:Bar[D]](bars: Set[T]) : util.Set[D] = bars.map(_.toD)
var javaSet : util.Set[Goo] = Set(new Moo)
现在它说你可以传递任何扩展Bar[D]
的类型,因此可以使用Moo