2010-07-22 4 views
3

EDIT 2:paramètres de type Utilisation et mixins à Scala

j'ai réussi à obtenir la sécurité de type que je voulais dans mon exercice avec une combinaison en utilisant numération romaine de mixins et des paramètres de type avec le code ci-dessous. En substance ce qu'il fait est après avoir importé tout dans RomanNumerals je peux écrire L X V I, mais pas L L ou X L X parce que je reçois une erreur de compilateur de type incompatibilité (puisque ceux-ci seraient des combinaisons illégales de chiffres romains). Maintenant, je me demande si cette façon d'utiliser les traits, les mixins et les paramètres de type est considérée comme correcte ou si j'abuse du langage pour ainsi dire :) Y a-t-il un meilleur moyen d'obtenir le même type de sécurité avec un système plus simple? code?

object RomanNumerals { 
    trait Numeral { 
    def num:Int 
    } 
    trait NumeralI[N<:Numeral] extends Numeral 
    trait NumeralV[N<:Numeral] extends NumeralI[N] { 
    def I = new RomanNumeral[Numeral](1 + this.num) with Numeral 
    def II = new RomanNumeral[Numeral](2 + this.num) with Numeral 
    def III = new RomanNumeral[Numeral](3 + this.num) with Numeral 
    } 

    trait NumeralX[N<:Numeral] extends NumeralV[N] { 
    def IV = new RomanNumeral[Numeral](4 
       + this.num) with Numeral 
    def V = new RomanNumeral[NumeralI[Numeral]](5 
      + this.num) with NumeralV[NumeralI[Numeral]] 
    def IX = new RomanNumeral[Numeral](9 
       + this.num) with Numeral 
    } 

    trait NumeralL[N<:Numeral] extends NumeralX[N] { 
    def X = new RomanNumeral[NumeralV[Numeral]](10 
      + this.num) with NumeralX[NumeralV[Numeral]] 
    def XX = new RomanNumeral[NumeralV[Numeral]](20 
       + this.num) with NumeralX[NumeralV[Numeral]] 
    def XXX = new RomanNumeral[NumeralV[Numeral]](30 
       + this.num) with NumeralX[NumeralV[Numeral]] 
    } 

    class RomanNumeral[T <: Numeral](val num:Int) { 
    override def toString = num toString 
    def apply[N >: T <: Numeral](rn:NumeralI[N]) = 
     new RomanNumeral[Numeral](rn.num + num) with Numeral 

    def apply[N >: T <: Numeral](rn:NumeralV[N]) = 
     new RomanNumeral[NumeralI[Numeral]](rn.num 
     + num) with NumeralV[NumeralI[Numeral]] 

    def apply[N >: T <: Numeral](rn:NumeralX[N]) = 
     new RomanNumeral[NumeralV[Numeral]](rn.num 
     + num) with NumeralX[NumeralV[Numeral]] 

    def apply[N >: T <: Numeral](rn:NumeralL[N]) = 
     new RomanNumeral[NumeralX[Numeral]](rn.num 
     + num) with NumeralL[NumeralX[Numeral]] 

    } 

    val I = new RomanNumeral[NumeralI[Numeral]](1) with NumeralI[Numeral] 
    val II = new RomanNumeral[NumeralI[Numeral]](2) with NumeralI[Numeral] 
    val III = new RomanNumeral[NumeralI[Numeral]](3) with NumeralI[Numeral] 
    val IV = new RomanNumeral[NumeralI[Numeral]](4) with NumeralI[Numeral] 
    val V = new RomanNumeral[NumeralI[Numeral]](5) with NumeralV[NumeralV[Numeral]] 
    val IX = new RomanNumeral[NumeralI[Numeral]](9) with NumeralI[Numeral] 
    val X = new RomanNumeral[NumeralV[Numeral]](10) with NumeralX[NumeralX[Numeral]] 
    val XX = new RomanNumeral[NumeralV[Numeral]](20) with NumeralX[NumeralX[Numeral]] 
    val XXX = new RomanNumeral[NumeralV[Numeral]](30) with NumeralX[NumeralX[Numeral]] 
    val XL = new RomanNumeral[NumeralV[Numeral]](40) with NumeralX[NumeralX[Numeral]] 
    val L = new RomanNumeral[NumeralX[Numeral]](50) with NumeralL[NumeralL[Numeral]] 
} 

EDIT:

question plus de base Victors answere. Ok, mais que se passe-t-il si j'ajoute des limites supérieures et inférieures au paramètre de type afin que B soit un trait? Par exemple.

trait Bar 
class Foo[T<:Bar](n:Int) { 
    def apply[B >: T <: Bar](f:Foo[B]) = { 
    new Foo[B](n + f.n) with B 
    } 
} 

Ou peut-être B peut encore être une classe dans ce cas? Que faire si je sais que l'argument f s'applique aussi est de type Foo[B] with B? Existe-t-il un moyen d'utiliser cela pour mixer B avec le type de retour?

QUESTION ORIGINAL CI-DESSOUS

Je veux mélanger dans un trait que je reçois en tant que paramètre de type lorsque je crée un objet à Scala:

class Foo(val num:Int) { 
    def withM[B](foo:Foo) = new Foo(foo.num) with B 
} 

Il en résulte une erreur de compilation:

error: class type required but B found 
def withM[B](foo:Foo) = new Foo(foo.num) with B 
              ^

J'ai aussi essayé:

class Foo(val num:Int) { 
    def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B] 
} 

Mais cela ne fonctionne pas:

error: not found: type classOf 
def withM[B](foo:Foo) = new Foo(foo.num) with classOf[B] 
              ^

est-il someway pour contourner cela? Alors que le type de retour de withM devient Foo with BB est le paramètre de type passé à withM

Répondre

5

Ce type de fonctionnalité est tout simplement impossible (ou disponible) , il est également possible de mixin traits (et interfaces), et votre paramètre de type pourrait être Int aussi loin que le compilateur le sait.

Vous devez spécifier un trait de béton ou le type d'interface afin:

trait T 
class Foo 
object Test { 
    def apply = new Foo with T 
} 
+0

Edité la question avec un peu plus d'informations/nouvelle question :) –