【问题标题】:Type mismatch with abstract types类型与抽象类型不匹配
【发布时间】:2016-03-28 07:56:51
【问题描述】:

我正在使用抽象类型,但在让 Scala 编译器统一两种应该相同的类型时遇到问题。这些是我的定义:

trait Chromosome {
  type Gene

  val size : Int

  def apply(idx : Int) : Gene

  def update(idx : Int, g : Gene)

  def indices = Range(0, size-1)
}


trait Individual {
  type Fitness
  implicit protected val ord: Ordered[Fitness] = implicitly[Ordered[Fitness]]

  val chromosome : Chromosome

  def size : Int = chromosome.size

  def apply(idx : Int) : chromosome.Gene = chromosome.apply(idx)
  def update(idx : Int, g : chromosome.Gene ) = chromosome.update(idx, g)

  protected var _fitness : Fitness = _
  def fitness : Fitness = _fitness
  def fitness_=(f : Fitness):Unit = _fitness = f
}


case class ArrayChromosome(size : Int) extends Chromosome {
  implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]

  protected val xs : Array[Gene] = new Array[Gene](size)

  def apply(idx : Int) = xs(idx)

  def update(idx : Int, g : Gene) = xs(idx) = g
}


abstract class ArrayIndividual(size : Int) extends Individual {
  val chromosome  = ArrayChromosome(size)
}


class MyIndividual(size : Int) extends ArrayIndividual(size) {
  type Gene = Int
  type Fitness = Double
}


object Test extends App {
  val i1 = new MyIndividual(10)

  i1.fitness = 10.5
  i1.chromosome(0) = 6
  print(i1)
}

即问题出在这一行:

i1.chromosome(0) = 6

类型错误是:

Error:(75, 22) type mismatch;
 found   : Int(6)
 required: abstractTypes.Test.i1.chromosome.Gene
  i1.chromosome(0) = 6

编译器似乎无法将i1.chromosome.GeneInt 统一起来。

我有两个问题:

  1. 是否可以帮助编译器统一这两种类型?
  2. 现在让我假设我已经删除了有问题的行并且我已经为Individuals 正确定义了toString。为什么我在运行Test 时会得到java.lang.NullPointerException。该错误似乎与GeneClassTag有关,但我不确定。

回复代码到@som-snytt:

abstract class ArrayIndividual(size : Int) extends Individual {
  type Gene
  implicit protected def tag2: ClassTag[Gene]

  val chromosome  = new ArrayChromosome(size) {
    type Gene = ArrayIndividual#Gene
    protected val tag : ClassTag[Gene] = tag2
  }
}

class MyIndividual(size : Int) extends ArrayIndividual(size) {
  type Fitness = Double
  type Gene = Int
  implicit protected val tag2 : ClassTag[Gene] = implicitly[ClassTag[Gene]]

  override def toString = s"${super.toString} $chromosome"
}

【问题讨论】:

    标签: scala abstract-type


    【解决方案1】:

    在 Scala 中,类型不是全局范围的。您已将Gene 编写为Chromosome 类型的成员,但您试图在Individual 的子类中定义它(“具有”Chromosome,而不是“是”Chromosome) .

    您可以选择在哪里声明和定义它,但它必须在同一层次结构中,就像您覆盖诸如方法之类的术语成员时一样。

    individual.Gene 与您的示例中的 chromosome.Gene 无关。

    将类型定义移动到 ClassTag 所需的位置:

    case class ArrayChromosome(size : Int) extends Chromosome {
      type Gene = Int
      implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]
    

    哦,我刚刚注意到您正在递归地定义您的隐式。 RHS 上的隐式使用您定义的隐式。所以不要那样做。编译器自己调用隐式。

    但是,如果您确实需要在未修复别名类型的超类中提供隐式标记,则可以使用抽象方法来提供将在具体类中实现的类标记。

    例如,让Individual 子类指定具体的Chromosome

    abstract class ArrayChromosome(val size : Int) extends Chromosome {
      //type Gene = Int
      //implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]]
      implicit protected def tag: ClassTag[Gene]
    
      protected lazy val xs : Array[Gene] = new Array[Gene](size)
    
      def apply(idx : Int) = xs(idx)
    
      def update(idx : Int, g : Gene) = xs(idx) = g
    }
    
    
    abstract class ArrayIndividual(size : Int) extends Individual {
      //val chromosome  = ArrayChromosome(size)
      val chromosome  = new ArrayChromosome(size) {
        type Gene = Int
        protected val tag = implicitly[ClassTag[Gene]]
      }
    }
    
    
    class MyIndividual(size : Int) extends ArrayIndividual(size) {
      type Fitness = Double
    
      override def toString = s"${super.toString} $chromosome"
    }
    

    【讨论】:

    • 感谢您的回答,但类型 Gene 在 ArrayChromosome 类中应该是抽象的,并且只能在稍后在扩展该类的子类中定义。我想我可以添加一个类型参数,但是没有这个参数是否可以解决统一问题?
    • 这就是我所说的关于标签的评论的意思。我将添加代码示例。
    • 注意惰性值。
    • 非常感谢您的回答,但问题是ArrayIndividual 类中的Gene 应该是抽象的,并且只能在稍后在子类中实例化,例如MyIndividual。我试图用我在上面的问题末尾添加的代码来做到这一点,在那里我尝试将 ArrayIndividual 类中的抽象类型 Genechormosome 中使用的 Gene 的类型统一起来但这仍然失败并出现错误。似乎 Scala 编译器无法统一这两种类型,即使在提供了相等性之后也是如此。你知道如何解决这个问题吗?
    • 您在不相关的范围内引入了名称Gene。两种用法是苹果和橙子。希望我的编辑有所帮助。
    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 2017-02-04
    • 2010-09-20
    • 2016-09-04
    • 2010-11-08
    • 2022-01-09
    • 1970-01-01
    • 2018-06-08
    相关资源
    最近更新 更多