J'ai une paire de classes qui ressemble à quelque chose comme ça. Il y a un Generator
qui génère une valeur basée sur certaines valeurs de niveau classe, et une GeneratorFactory
qui construit un Generator
.
case class Generator[T, S](a: T, b: T, c: T) {
def generate(implicit bf: CanBuildFrom[S, T, S]): S =
bf() += (a, b, c) result
}
case class GeneratorFactory[T]() {
def build[S <% Seq[T]](seq: S) = Generator[T, S](seq(0), seq(1), seq(2))
}
Vous remarquerez que GeneratorFactory.build
accepte un argument de type S
y Generator.generate
produit une valeur de type S
mais il n'y a rien de type S
stocké par le Generator
.
Nous pouvons utiliser les classes comme ceci. La fabrique travaille sur une séquence de Char
et generate
produit un String
parce que build
se voit attribuer un String
.
val gb = GeneratorFactory[Char]()
val g = gb.build("this string")
val o = g.generate
Cela fonctionne bien et permet de gérer le String
implicitement parce que nous utilisons le type GeneratorFactory
.
Le problème
Le problème se pose maintenant lorsque je veux construire une Generator
sans passer par l'usine. J'aimerais pouvoir le faire :
val g2 = Generator('a', 'b', 'c')
g2.generate // error
Mais je reçois une erreur parce que g2
a un type Generator[Char,Nothing]
et Scala "Cannot construct a collection of type Nothing with elements of type Char based on a collection of type Nothing".
Ce que je veux, c'est un moyen d'indiquer à Scala que la "valeur par défaut" de l'option S
est quelque chose comme Seq[T]
au lieu de Nothing
. En s'inspirant de la syntaxe des paramètres par défaut, on pourrait penser que c'est quelque chose comme :
case class Generator[T, S=Seq[T]]
Des solutions insuffisantes
Bien sûr, cela fonctionne si nous indiquons explicitement au générateur quel doit être son type généré, mais je pense qu'une option par défaut serait plus agréable (mon scénario réel est plus complexe) :
val g3 = Generator[Char, String]('a', 'b', 'c')
val o3 = g3.generate // works fine, o3 has type String
J'ai pensé à surcharger Generator.apply
pour avoir une version à un seul type générique, mais cela provoque une erreur car, apparemment, Scala ne peut pas faire la différence entre les deux apply
définitions :
object Generator {
def apply[T](a: T, b: T, c: T) = new Generator[T, Seq[T]](a, b, c)
}
val g2 = Generator('a', 'b', 'c') // error: ambiguous reference to overloaded definition
Sortie souhaitée
Ce que je voudrais, c'est un moyen de construire simplement une Generator
sans spécifier le type S
et le faire passer par défaut à Seq[T]
pour que je puisse le faire :
val g2 = Generator('a', 'b', 'c')
val o2 = g2.generate
// o2 is of type Seq[Char]
Je pense que ce serait l'interface la plus propre pour l'utilisateur.
Avez-vous une idée de la façon dont je peux y parvenir ?