两个耦合的Scala泛型类型构造函数如何相互引用作为类型参数?

时间:2011-04-07 11:15:55

标签: generics scala scala-2.8 scala-java-interop

在Java 1.6.0_21中,下面的第一个例子编译得很好,我认为那是因为参数类型边界是裸的。也就是说,在下面的“Z extends Zen”中,Java允许 Zen作为原始非泛型类型的名称滑动(相当于运行时“擦除” 类型)。这可能是错误的和坏的,但它也可能是有用的,或者至少是古怪的 乘坐巴士回家的好时光:

public class CorefTest {

    public static interface Tao<Z extends Zen> {
    }

    public static interface Zen<T extends Tao> {
    }
}

在Scala 2.8.0.final中,下面通过CleanOceanWithFish进行编译,显示 一些基本类型的param连接。但是当我们得到禅和陶是相互依存的时候 通用类型,Scala编译器拒绝我的编织结构。请参阅注释中的编译器错误。

package heaven.piece
class Lucky {
    trait Water {}
    trait CleanWater extends Water {}
    trait Sea [W <: Water] {}
    trait Fish[S <: Sea[CleanWater]] {}

    trait CleanOceanWithFish[F <: Fish[CleanOceanWithFish[F]]] 
                   extends Sea[CleanWater]{}

// Above code compiles fine, but the type constructor pair below doesn't compile 

    trait Tao[Z <: Zen[Tao[Z]]]{};

    trait Zen[T <: Tao[Zen[T]]]{};
}
// error: type arguments [Lucky.this.Tao[Z]] do not conform to trait Zen's 
//     type parameter bounds [T <: Lucky.this.Tao[Lucky.this.Zen[T]]]

// error: type arguments [Lucky.this.Zen[T]] do not conform to trait Tao's 
//     type parameter bounds [Z <: Lucky.this.Zen[Lucky.this.Tao[Z]]]

那么,我怎样才能在道与禅之间正确绑定Scala(2.8.0)结?

这当然是一个人为的例子,但我真正想要的是使用Scala来扩展 我在上面的表单中工作的一些真正的Java类型(通过“forSome”和“[_]”存在类型到目前为止并没有帮助我)。我认为得到禅和道 在Scala中编译可能会显示到Java扩展的方式。如果您可以在答案中考虑Java扩展问题,那就更好了。谢谢你的帮助!

更新在Nikita S.和Kris N的下面非常有用的前两个答案之后发布。

我凭经验学习了更多关于各种Java + Scala共同参考方案的知识。结果是当我们想要 Java和Scala中的可互操作的共同类型时,那么这个Java构造:

public static interface JavaFunTao<JFZ extends JavaFunZen<? extends JavaFunTao<JFZ>>> {
    public JFZ consider(JFZ someZen, JavaFunTao<JFZ> otherTao);
}
public static interface JavaFunZen<JFT extends JavaFunTao<? extends JavaFunZen<JFT>>> { 
    public JFT meditate(JFT someTao, JavaFunZen<JFT> otherZen);
}

提供比我在顶部的第一个Java示例(避免原始类型)更具体的类型,然后在Scala中可以正确扩展,如下所示:

class HiFunTao[HFZ <: HiFunZen[  _ <: HiFunTao [HFZ]]] extends JavaFunTao[ HFZ] {
    override def consider(someZen: HFZ, otherTao: JavaFunTao[HFZ]) : HFZ = {
        println (this.toString() + " is considering " + someZen + " and " + otherTao);
        someZen
    }
}
class HiFunZen[HFT <: HiFunTao[ _ <:  HiFunZen [HFT]]] extends JavaFunZen[ HFT] {
    override def meditate(someTao: HFT, otherZen: JavaFunZen[HFT]) : HFT = {
        println (this.toString() + " is meditating on " + someTao + " and " + otherZen);
        someTao
    }
}

我验证了我们可以根据这些类型制作简单的具体类型,实例化它们并调用它们的方法。 Java和Scala中的关键步骤是将有界通配符放置在类型参数树循环回当前声明类型的位置,即java中的“?extends”和Scala中的“_&lt;:” 。

2 个答案:

答案 0 :(得分:3)

既然Zen和Tao都不是协变的,那么你的zen和tao就存在可替代性问题。这对2.8.1下的编译很好:

trait Tao[+Z <: Zen[Tao[Z]]]

trait Zen[+T <: Tao[Zen[T]]]

当然,如果你想冥想Z或T,那么这对你来说也不会起作用,至少不完全如上所述,因为在逆变位置有一个协变型参数的问题。你可以解决这个问题:

trait Tao[+Z <: Zen[Tao[Z]]] {
  def meditate[M >: Z](m: M) = ()
}

trait Zen[+T <: Tao[Zen[T]]] {
  def meditate[M >: T](m: M) = ()
}

但是这可能仍会对您可能不需要的实现产生约束。这至少令人困惑。 :)

<强>更新

顺便说一句,这也避免了更新NSkvortsov答案中提到的问题。编译好了:

class Zazen extends Zen[Tao[Zazen]]

答案 1 :(得分:2)

我认为,这就是你所需要的:

class MyClass {

  trait Tao[Z <: Zen[_]]{};
  trait Zen[T <: Tao[_]]{};

}

此代码段由Scala 2.8.1

成功编译

<强>更新

不幸的是,在scala中扩展CorefTest.ZenCorefTest.Tao是不可能的。这就是原因。

java 中实现接口的唯一方法是使用原始类型

public class TaoImpl<Z extends CorefTest.Zen> implements CorefTest.Tao<Z> { }

public class ZenImpl<T extends CorefTest.Tao> implements CorefTest.Zen<T> { }

可以实例化这样的类:

TaoImpl<ZenImpl> tao = new TaoImpl<ZenImpl>();
ZenImpl<TaoImpl> zen = new ZenImpl<TaoImpl>();

scala 不支持原始类型。因此无法定义TaoImplZenImpl。 请参阅此e-mail thread并发帖#2091#1737进行详细讨论