Question

J'ai une classe abstraite:

abstract class Foo(...){
   def bar1(f : Foo) : Boolean
   def bar2(f : Foo) : Foo
}

plusieurs classes étendent Foo et remplacent les méthodes

class FooImpl(...) extends Foo{
    override def bar1(f : Foo) : Boolean {
        ...
    }
    override def bar2(f : Foo) : Foo {
        ...
    }
} 

Est-il possible, en utilisant des génériques (ou quelque chose) pour que les méthodes prépondérants ont le ParameterType de la sous-classe sa mise en œuvre? Comme ceci:

class FooImpl(...) extends Foo{
    override def bar1(f : FooImpl) : Boolean {
        ...
    }
    override def bar2(f : FooImpl) : FooImpl {
        ...
    }
}

Je pensais quelque chose le long de la ligne de ce qui suit, mais cela ne semble pas fonctionner ...

abstract class Foo(...){
    def bar1[T <: Foo](f : T) : Boolean
    def bar2[T <: Foo](f : T) : T
}

class FooImpl(...) extends Foo{
    override def bar1[FooImpl](f : FooImpl) : Boolean {
       ...
    }
    override def bar2[FooImpl](f : FooImpl) : FooImpl{
       ...
    }
}

Toute aide est très appréciée!

Merci.

Était-ce utile?

La solution

abstract class Foo{
   type T <: Foo
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo{
   type T = FooImpl
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

Dans cette version, les différentes sous-classes de Foo toutes Foo d'actions comme superclasse, mais pour maintenir la valeur de retour de bar2 (ou les paramètres à bar1 ou bar2) dans un contexte où tout ce que vous savez sur votre objet (disons qu'il est nommé obj) est que c'est un Foo, vous devez utiliser le obj.T de type que le type de la variable.

Autres conseils

Pour faire deuxième version un peu de peu de Ken Blum plus agréable, vous pouvez utiliser les types d'auto:

abstract class Foo[T] { self:T =>
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

besoins de T pour être un paramètre de type sur la classe Foo que vous héritez de, non pas sur les méthodes elles-mêmes.

abstract class Foo[T <: Foo[T]]{
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

Les différentes sous-classes de Foo n'ont pas fait une commune supertype dans cette version du code, car ils vont de différentes paramétrisation de Foo. Vous pouvez utiliser des méthodes paramétrées qui se réfèrent à Foo[T] lorsque vous avez besoin de travailler avec le supertype commun, mais je tendance à préférer la solution de type abstrait que j'ai posté dans mon autre réponse, car du coup il ne fuit pas les détails des génériques à tous les d'autres fonctions qui doivent faire face à Foos.

Idéalement, vous combinez les choses mentionnées ci-dessus, i.e..

trait Foo[T <: Foo[T]] { self:T =>

"[T <: Foo [T]]" T est un moyen de sous-classe Foo [T], ET « auto: T => ». Foo signifie que [T] est sous-classe de T, et en même temps, il est un peu étrange façon de dire que Foo [T] est exactement le même que T

Seulement avec que je pouvais faire du code ci-dessous et la compilation fonctionnent comme prévu:

trait Field[T <: Field[T]] { self:T =>

  def x2:T

  def +(that:T):T

  def *(n:BigInt) : T = {
    if(n == 1)
      this
    else if(n == 2)
      this.x2
    else if(n == 3)
      this + this.x2
    else {
      val p = (this * (n/2)).x2
      if (n%2==0)
        p
      else
        p + this
    }        
  }

}

Vous pouvez paramétrer Foo pour accomplir une partie de l'effet facilement:

abstract class Foo[F <: Foo[F]] { def f: F }
class Food extends Foo[Food] { def f = this }  // Yay!
class Fool extends Foo[Food] { def f = new Food }  // Uh-oh...

Si vous voulez exclure le deuxième cas, il n'y a aucun moyen simple de le faire avec les caractéristiques actuelles de Scala.

En outre, certains de ce que vous semblez vouloir ne pas de sens si vous donnez une mise en œuvre effective dans Foo. Si les promesses de Foo de prendre toute Foo mais vous donnent une méthode qui insiste sur seulement Food, il se brisera si vous vous passez une sous-classe différente de Foo (par exemple Fool). Donc, le compilateur ne vous laissera pas faire.

abstract class Foo { def bar(f: Foo) : Foo }
class Foot extends Foo { def bar(f: Foo) = this }   // Fine!
class Fool extends Foo { def bar(f: Fool) = this }   // No good!
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top