Scala-Typ überschreiben

EDITED AFTER TWO ANSWERS BELOW I am trying to make the following Scala code to compile.

  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)
  }

Scheitert aber mit folgender Meldung:

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

Irgendeine Idee?

Grundsätzlich möchte ich eine generische Klasse wie C oben definieren und Methoden mit dem richtigen Typ für eine Unterklasse (C1) haben.

Alles ist gut, bis in soSthg eine generische Methode aufgerufen wird.

Vielen Dank

NEUE BEARBEITUNGSABSCHNITT

Vielen Dank v much for your replies. Looking at the following code, I was hoping to avoid 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
    }
  }

Die Signatur von x (anders: C [Boolean]) ist in der Tat das Problem.

Das würde funktionieren:

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

Wie asInstanceOf zu vermeiden?

0

2 Antworten

C1 compiles fine. Note that you could remove override keyword here:

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

doSthg is just invalid: you can't prove that e2 is e1.T. This works as expected:

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

Oder dieses:

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

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

Für Ihre ursprüngliche doSthg -Methode sollte x jede Instanz von C akzeptieren:

trait C {
  def x(other: C): (C, C)
}
0
hinzugefügt

There's no problem defining C & C1 as above. The problem is that you're passing an argument to e1.x that is of type C (not C1) and so violates your C1.x method signature.

Soweit der Compiler betroffen ist:

  1. You're modelling a type hierarchy rooted at trait/class C
  2. Inside doSthg, the vals e1 & e2 are each of some type within the hierarchy. For e1 & e2, the only things known for sure are that e1.type and e2.type are each subtypes of C. There's no guarantee that e1 and e2 are of the same type (or are subtypes of one another) - even though the class hierarchy is very shallow (just one subclass, C1). You could extend by adding new subtypes of C in new .class/.jar files at any point in the future (possibly generated from .scala/.java files from this compiler on this machine, or even by a different compiler on a different machine!)
  3. You have chosen that your method C1.x is not flexible - it's argument must be of type C1, not any C. Hence, e1.x cannot take an 'arbitrary' e2 <: C as argument.

Der Compiler macht also das Richtige, basierend auf Ihren Designentscheidungen. Lösungen:

  • allow C1.x to take arguments of type C
  • make doSthg argument List[C1] (possibly moving doSthg within C1 at the same time)
0
hinzugefügt
Tatsächlich. So etwas würde funktionieren: def doSthg2 [T <: C] (csl: Liste [T]) {csl (0) .x (csl (1))}
hinzugefügt der Autor jts, Quelle