Voici ce que je crois se passe. Tout d'abord, S
est le même type partout, il n'y a pas de magie ici. Regardons le premier exemple:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = if(t1.isEmpty) t1 else t2
cons: [S <: List[Any]](t1: S, t2: S)S
scala> cons(List(1), List(2.0))
res21: List[AnyVal] = List(2.0)
Comme vous pouvez le voir Scala le plus proche a constaté à juste ancêtre commun pour Int
et Double
, et il est AnyVal
. Donc, dans ce cas S
est AnyVal
.
Maintenant, nous allons essayer ceci:
scala> def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
<console>:11: error: type mismatch;
found : List[Any]
required: S
def cons[S <: List[Any]](t1: S, t2: S): S = t1 ++ t2
^
Quel est le problème? Ce message d'erreur signifie que le résultat de ++
est en quelque sorte List[Any]
au lieu de prévu S
. Pourquoi donc? Regardons la signature ++
(simplifié, est plus vraie signature):
def ++[B >: A](other: List[B]): List[B] = ???
Alors Scala doit trouver l'ancêtre le plus proche de A
et le paramètre de type réel de other
. Le seul problème est: il doit trouver B
au point où vous définissez cons
, pas où vous l'appliquez plus tard (B
n'est pas un paramètre libre pour cons
). La seule information est la limite supérieure de S
, et c'est List[Any]
, donc la seule solution sûre pour B
au point de définition de cons
est la plus générique, c'est-à-dire Any
. Ce qui signifie que le résultat de ++
est List[Any]
, et il ne rentre pas S
. D'où l'erreur.
Troisième exemple:
scala> def cons[S <: Any](t1: List[S], t2: List[S]): List[S] = t1 ++ t2
cons: [S](t1: List[S], t2: List[S])List[S]
scala> cons(List(1), List(1.0))
res0: List[AnyVal] = List(1, 1.0)
Pourquoi ce travail? Ici, les deux t1
et t2
ont exactement le même type, peu importe ce que S
est (et S
peut être inféré plus tard). Donc B == S
et le résultat est List[S]
. Encore dans ce cas particulier S
est l'ancêtre commun le plus proche de Int
et Double
.
Dans votre troisième exemple, vous dites "Ici, t1 et t2 ont exactement le même type, peu importe ce que S est". Comment cela peut-il être? Liste [Int] Liste [Double] sont de différents types arent ils? – Samar
Je pense que la confusion se produit parce que différents types peuvent être initialement passés en arguments, mais le type de S sera l'ancêtre commun le plus proche des différents types passés. – Samar
Je seconde les questions de Samar. Je ne vois pas de différence entre '(t1: S, t2: S)' et '(t1: liste [S], t2: liste [S])'. Dans les deux cas t1 et t2 ont exactement le même type. Bien sûr, vous pouvez passer 'List [Int]' et 'List [String]', mais dans ce cas, l'ancêtre le plus proche est 'List [Any]', donc c'est ce que 'S' est. Pouvez-vous donner un exemple pour 'def contre [S <: List [Any]] (t1: S, t2: S): S' où nous aurions une erreur (d'où le compilateur ne le permet pas)? Quoi que vous passiez, le compilateur déduira que 'S' est l'ancêtre le plus proche et ** c'est ce qui sera retourné **. Type inféré 'S'. Ça devrait marcher avec 'S', non? – slouc