从scala设置到Java Set的隐式转换

net*_*tta 2 scala implicit-conversion

我有以下内容:

    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!!!
    }
Run Code Online (Sandbox Code Playgroud)

当我尝试编译此代码时,我收到一个错误:

"error: type mismatch;
   found   : scala.collection.immutable.Set[Moo]
   required: java.util.Set[Goo]
           var javaSet : util.Set[Goo] = ***Set(new Moo)***"
Run Code Online (Sandbox Code Playgroud)

显式定义编译.为什么隐式转换不起作用?

0__*_*0__ 7

这确实很棘手.基本上你的想法是正确的.您可以定义scalaSetToJavaSet导入的转换方法.问题来自于(Scala's)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
Run Code Online (Sandbox Code Playgroud)

您现在可以这样理解:给定类型DBar类型参数的某个子类型D,进行转换.此方法现在称为scalaSetToJavaSet[Goo, Moo](而不是scalaSetToJavaSet[Goo, Bar[Goo]]).


正如其他人所指出的那样,使用现成的转换更容易,JavaConversions而不是自己编写.