2016-02-06 5 views

Répondre

0

L'auto type self: T => implique que votre Foo[T] doit aussi être un T. new Foo[T] { ... } n'est pas une instance de T pour tout T arbitraire qui compose Foo[T]. Vous ne pouvez pas non plus ajouter un self-type à une classe anonyme comme new Foo[T] { ... }, car cela n'a pas de sens. Soit la classe concrète est ou n'est pas T à ce stade.

Construire une méthode comme def newFoo: Foo[T] d'une manière sécurisée par type n'est pas vraiment possible avec l'auto-type en place, parce que vous auriez besoin de savoir comment construire un arbitraire T. Vous pourriez être en mesure de faire ce que vous voulez avec la réflexion, quand chaque T a le même constructeur.

import scala.reflect._ 

abstract class Foo[T <: Foo[T] : ClassTag] { self: T => 
    def bar(x: T): T 
    def newFoo: Foo[T] = classTag[T].runtimeClass.newInstance.asInstanceOf[T] 
} 

class Bar extends Foo[Bar] { 
    def bar(x: Bar): Bar = x 
} 

scala> val b = new Bar 
b: Bar = [email protected] 

scala> b.newFoo 
res1: Foo[Bar] = [email protected] 

Ce cesse de travailler quand il y a des paramètres du constructeur:

case class Baz(i: Int) extends Foo[Baz] { 
    def bar(x: Baz): Baz = x 
} 

scala> val baz = new Baz(0) 
baz: Baz = Baz(0) 

scala> baz.newFoo 
java.lang.InstantiationException: Baz 
    at java.lang.Class.newInstance(Class.java:427) 
    at Foo.newFoo(<console>:16) 
+0

Eh bien, vous connaissez déjà la classe de T même sans balises de classe, et c'est exactement à cause du self-type: self a le type T donc avec self.getClass vous obtenez la classe que vous voulez. – dth

+0

Vrai, mais cela ne vous servira à rien s'il a des paramètres constructeur. –

+0

Non, en effet. Vous pouvez bien entendu aussi obtenir les autres constructeurs de cette façon, mais la question demeure, d'où vous obtiendriez les arguments. – dth

0

Eh bien, vous ne connaissez pas la classe concrète où Foo sera héritée à l'avenir. Donc, surtout, vous ne savez pas quels paramètres constructeurs cette classe aura et comment fournir des arguments pour eux. Si vous voulez vraiment faire cela, vous devrez faire quelques suppositions (que vous ne pouvez pas appliquer à la compilation) pour y parvenir.

Donc ce que vous devriez probablement faire, c'est de laisser cette méthode abstraite et de l'implémenter dans une sous-classe. Si ce n'est pas une option, vous avez probablement des problèmes avec la conception globale de votre classe. Mieux vaut présenter ici ce que vous voulez modéliser et demander de l'aide.

Si vous assumez, que le constructeur de la classe concrète n'aura aucun paramètre, vous pouvez mettre en œuvre newFoo comme

def newFoo = this.getClass.newInstance 

Il n'y a pas besoin de classTags ou d'autres choses de fantaisie.