繁体   English   中英

如何避免可怕的类型转换与路径相关的类型一起使用?

[英]How to avoid awful type casts working with path dependent types?

我是Scala的新手,不知道为什么我必须在以下代码中进行与路径依赖类型相关的(对我来说是不直观的)类型转换。 (我不喜欢getter,setter或null,它们在这里是分开操作并消除错误根源的歧义)

// Module A public API
class ModA {
  trait A
}

// Module B public API that depends on types defined in Module A
class ModB(val modA: ModA) {
  trait B {
    def getA: modA.A;
    def setA(anA: modA.A);
  }
}

// One implementation of Module A
class ModAImpl extends ModA {
  class AImpl extends A
}

// One implementation of Module B
class ModBImpl(mod: ModA) extends ModB(mod) {
  class BImpl extends B {
    private[this] var privA: modA.A = _;
    override def getA = privA;
    override def setA(anA: modA.A) = privA = anA;
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    // wiring the modules
    val modAImpl = new ModAImpl;
    val modBImpl = new ModBImpl(modAImpl);

    // wiring objects
    val a = new modAImpl.AImpl;
    val b = new modBImpl.BImpl;
    b.setA(a); //don't compile and complain: type mismatch;  found: modAImpl.A  required: modBImpl.modA.A

    //i have to do this horrible and coutnerintuitive cast to workaround it
    b.setA(a.asInstanceOf[modBImpl.modA.A]);

    var someA: modAImpl.A = null;
    someA = b.getA; // don't compile with same reason
    someA = b.getA.asInstanceOf[modAImpl.A]; // horrible cast to workaround

    println(a == b.getA); // however this prints true
    println(a eq b.getA); // this prints true too
  }
} 

我已经阅读了有关单例类型的信息,以便在两种类型相同时通知编译器,但我不知道如何在此处应用该类型。 提前致谢。

您可以在ModB类型上粘贴类型参数:

class ModA { trait A }

class ModB[AA](val modA: ModA { type A = AA }) {
  trait B {
    def getA: AA
    def setA(anA: AA)
  }
}

class ModAImpl extends ModA { class AImpl extends A }

class ModBImpl[AA](
  mod: ModA { type A = AA }) extends ModB(mod) {
  class BImpl extends B {
    private[this] var privA: AA = _
    override def getA = privA
    override def setA(anA: AA) = privA = anA
  }
}

并且类型推断都可以按需完成:

scala> val modAImpl = new ModAImpl
modAImpl: ModAImpl = ModAImpl@7139edf6

scala> val modBImpl = new ModBImpl(modAImpl)
modBImpl: ModBImpl[modAImpl.A] = ModBImpl@1dd7b098

scala> val a = new modAImpl.AImpl
a: modAImpl.AImpl = ModAImpl$AImpl@4cbde97a

scala> val b = new modBImpl.BImpl
b: modBImpl.BImpl = ModBImpl$BImpl@63dfafd6

scala> b.setA(a)

让我们从简化代码开始,消除不必要的复杂性。

class Aout {
    class Ain
}

class Bout(val link: Aout)  {
    class Bin(val field: link.Ain)
}

object Main {
    def main(args: Array[String]): Unit = {
        // wiring outer object
        val aout: Aout = new Aout;
        val bout: Bout = new Bout(aout);

        // wiring inner object
        val ain: aout.Ain = new aout.Ain;
        val bin: bout.Bin = new bout.Bin(ain); //don't compile and complain: type mismatch;  found: aout.Ain  required: bout.link.Ain
    }
}

回答:

编译器抱怨类型不匹配错误,因为他比较了赋值中涉及的两个声明的类型的路径,并且它们是不同的。 编译器不够智能,无法注意到此时的aout eq bout.link 你必须告诉他。 因此,更换线

val ain: aout.Ain = new aout.Ain;

val ain: bout.link.Ain = new bout.link.Ain;

解决了与路径有关的类型不匹配的问题。

无论如何,仅在原始代码中更正类型的路径是不够的,因为还存在继承问题。 一种解决方案是使类ModBImpl知道ModAImpl类,如下所示:

class ModA {
    trait A
}

class ModB[M <: ModA](val modA: M) { // type parameter added
    trait B {
        def getA: modA.A;
        def setA(anA: modA.A);
    }
}

class ModAImpl extends ModA {
    class AImpl extends A
}

class ModBImpl(mod: ModAImpl) extends ModB(mod) { // changed type of `mod` parameter from `ModA` to `ModAImpl`

    class BImpl extends B {
        private[this] var privA: modA.A = _;
        override def getA: modA.A = privA;
        override def setA(anA: modA.A): Unit = privA = anA;
    }
}

object Main {
    def main(args: Array[String]): Unit = {
        val modAImpl = new ModAImpl;
        val modBImpl = new ModBImpl(modAImpl);

        val a: modBImpl.modA.AImpl = new modBImpl.modA.AImpl; // changed the path of the type
        val b: modBImpl.BImpl = new modBImpl.BImpl;
        b.setA(a); // here IntellijIde complains with a type mismatch error, but the ScalaIDE (eclipse) and the scala compiler work fine.
    }
}

如果您的业务规则不允许ModBImpl类了解ModAImpl类,请告诉我,以便我们找到其他解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM