2

我有以下内容:

    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)***"

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

4

2 回答 2

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

您现在可以将其解读为:给定一个类型和其类型参数为 的D某个子类型,进行转换。此方法现在称为(而不是)。BarDscalaSetToJavaSet[Goo, Moo]scalaSetToJavaSet[Goo, Bar[Goo]]


正如其他人指出的那样,使用现成的转换比JavaConversions自己编写更容易。

于 2013-09-30T12:37:07.683 回答
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 一起使用

于 2013-09-30T12:38:10.297 回答