Scala类型覆盖

时间:2013-12-16 17:07:28

标签: scala

在以下两个答案之后编辑 我正在尝试编译以下Scala代码。

  abstract class C {
    type T <: C
    def x(other: T): (T, T)
  }

  class C1 extends C {
    override type T = C1
    override def x(other: C1): (C1, C1) = (this, this)
  }

  def doSthg(cs1 : List[C]) {
    val e1 = cs1(0)
    val e2 = cs1(1)

    e1.x(e2)
  }

但是失败并显示以下消息:

Description Resource    Path    Location    Type
type mismatch;  found   : e2.type (with underlying type Chromo[G])  required: e1.C  PI3.sc  /GA/src/org/jts/ga  line 76 Scala Problem
type mismatch;  found   : e2.type (with underlying type org.jts.ga.MI2.C)  required: e1.T   MI2.sc  /GA/src/org/jts/ga  line 18 Scala Problem

有什么想法吗?

基本上,我想在上面定义一个像C这样的泛型类,并在子类(C1)上使用正确类型的方法。

在soSthg中对C调用泛型方法之前,一切都很好。

由于

新编辑部分

非常感谢您的回复。 看下面的代码,我希望避免使用asInstanceOf。

  abstract class G[T](val t: T) {
    def ~(): G[T]
  }
  abstract class C[T](val g: List[G[T]]) {
    def x(other: C[T]): (C[T], C[T])
  }

  class G1(override val t: Boolean) extends G[Boolean](t){
    override def ~() = new G1(!t)
  }

  class C1(override val g: List[G1]) extends C[Boolean](g) {
    override def x(other: C[Boolean]): (C[Boolean], C[Boolean]) = {
      val go = other.g.map(e => e.asInstanceOf[G1])
      //val go = other.g
      val nc1 = new C1(go)
      (nc1, nc1) // for demo
    }
  }

x的签名(其他:C [布尔])确实是个问题。

这样可行:

def doSthg2[T <: C](csl : List[T]) { csl(0).x(csl(1)) }

如何避免asInstanceOf?

2 个答案:

答案 0 :(得分:10)

C1编译好。请注意,您可以在此处删除override关键字:

class C1 extends C {
  type T = C1
  def x(other: C1): (C1, C1) = (this, this) // do you mean (other, this)?
}

doSthg无效:您无法证明e2e1.T。这按预期工作:

def doSthg(e1: C)(e2: e1.T) {
  e1.x(e2)
}

或者这个:

abstract class C {
  ...
  def create(): T
}

def doSthg(e1: C) {
  val e2 = e1.create()
  e1.x(e2)
}

对于原始的doSthg方法,x应接受C的任何实例:

trait C {
  def x(other: C): (C, C)
}

答案 1 :(得分:1)

定义C&amp; C是没有问题的C1如上。问题是你将一个参数传递给了类型为C(而不是C1)的e1.x,因此违反了你的C1.x方法签名。

就编译器而言:

  1. 您正在建模一个以特征/类C
  2. 为根的类型层次结构
  3. doSthg内,val e1&amp; e2是层次结构中的某种类型。对于e1&amp; e2,唯一确定的事情是e1.typee2.type都是C的子类型。 没有保证e1e2具有相同的类型(或者是彼此的子类型) - 即使类层次结构非常浅(只是一个子类,{ {1}})。你可以通过在将来的任何一点在新的.class / .jar文件中添加C1的新子类型来扩展(可能是从这台机器上的编译器的.scala / .java文件生成的,甚至是由不同的编译器生成的)在另一台机器上!)
  4. 您选择的方法C不灵活 - 它的参数必须是C1.x类型,而不是C1。因此,C不能将“任意”e1.x作为参数。
  5. 因此编译器根据您的设计决策做正确的事情。解决方案:

    • 允许e2 <: C获取C1.x
    • 类型的参数
    • 制作doSthg参数C(可能同时在C1内移动doSthg)