2017-07-22 7 views
1

Code Scala:classe de retour extension générique trait à Scala

trait Converter[S, T] { 
    def convert(source: S): T 
} 

class StringDuplicatorConverter extends Converter[Integer, String] { 
    override def convert(source: Integer): String = { 
    source.toString + source.toString 
    } 
} 

// whatever, the point is to show potentially many 'converters' 
// from Integer (for example) to something 
class SomeOtherConverter extends Converter[Integer, User] { 
    override def convert(source: Integer): User = { 
    User(source) 
    } 
} 

trait ConverterProvider { 
    def getConverter[N]: Converter[Integer, N] 
} 

class MyClass extends ConverterProvider { 
    override def getConverter[N]: Converter[Integer, N] = { 
    new StringDuplicatorConverter() 
    } 
} 

donne

Error:(17, 5) type mismatch; 
found : StringDuplicatorConverter 
required: Converter[Integer,N] 
    new StringDuplicatorConverter() 

Répondre

1

Il peut être que ce que vous voulez vraiment est pour chaque ConverterProvider pour fournir un convertisseur à un type spécifique (sinon la définition de MyClass ne fait pas beaucoup de sens: elle doit retourner des convertisseurs différents pour différents N , pas toujours StringDuplicatorConverter). Si oui, la définition correcte est

trait ConverterProvider[N] { 
    def getConverter: Converter[Integer, N] 
} 

class MyClass extends ConverterProvider[String] { 
    override def getConverter: Converter[Integer, String] = { 
    new StringDuplicatorConverter() 
    } 
} 
1

Oui. Un appel à getConverter[N] est supposé renvoyer quelque chose de type Converter[Integer,N] mais StringDuplicatorConverter est de type Converter[Integer,String]. Depuis N n'est pas limité à String, et donc ils sont des types différents, cela ne compilera pas.

Si le compilateur recevait une certaine garantie que N est un, ou super-type de, String alors cela fonctionnerait. Cela peut être fait en faisant le covariant type de retour ...

trait Converter[S, +T] { ... 

... puis définir getConverter, et la dérogation, comme ceci:

def getConverter[N >: String]: Converter[Integer, N] 

Maintenant, il compile et semble fonctionner.

val mc = new MyClass 
mc.getConverter.convert(7) // res0: String = 77