2013-07-25 2 views
1

J'essayais de résoudre le problème 7 du 99 Scala Problems et j'ai rencontré quelques difficultés à trouver le type d'un List qui peut contenir n'importe quel type. J'ai donc regardé la réponse et j'ai vu que c'était List[Any]. Je continuai à coder sur une mise en œuvre comme suit:Scala: Pourquoi isInstanceOf [List [Any]] ne fonctionne-t-il pas?

def flatten(lst: List[Any]): List[Any] = lst match { 
    case Nil => Nil 
    case x::xs => 
     (if (x.isInstanceOf[List[Any]]) { flatten(x) } else { List(x) }) ::: 
     flatten(xs) 
} 

Cependant, cela me donne l'erreur de compilation suivante:

[error] <filename omitted>:<line number omitted>: type mismatch; 
[error] found : Any 
[error] required: List[Any] 
[error]    (if (x.isInstanceOf[Any]) { flatten(x) } else {List(x) }) 
[error]             ^
[error] one error found 

Changer isInstanceOf[List[Any]] à isInstanceOf[List[_]] donne la même erreur de compilation.

Après une courte this solution, je mis en œuvre cette recherche google et consulter:

def flatten(lst: List[Any]): List[Any] = lst match { 
    case Nil => Nil 
    case x::xs => x match { 
     case x: List[_] => flatten(x) ::: flatten(xs) 
     case _ => x :: flatten(xs) 
    } 
} 

qui fonctionne parfaitement bien. Alors pourquoi le compilateur Scala pense-t-il que x a le type Any alors que, pour entrer dans ce bloc, il doit passer x.isInstanceOf[Any], ce qui le rend de type List[Any]? Est-ce un bug de compilateur, ou est-ce une partie de Scala que je ne comprends pas?

Merci!

Répondre

3

Dans votre code, x est la tête d'un List[Any]: c'est un Any, d'où le message d'erreur que vous obtenez. Vous devez le convertir en List[Any], ce qui vous permet de faire assez élégamment:

def flatten(lst: List[Any]): List[Any] = lst match { 
    case Nil    => Nil 
    case (x:List[Any])::xs => flatten(x) ::: flatten(xs) 
    case x::xs    => List(x) ::: flatten(xs) 
} 
+0

Merci Nicolas! C'est un grand oubli de ma part. – yanhan

2

Tout simplement parce qu'une valeur passe la vérification .isInstanceOf ne change pas son type. C'est toujours un Any. Mais il peut être jeté à List[Any]

Donc, je pense que vous devez faire

(if (x.isInstanceOf[List[Any]]) { flatten(x.asInstanceOf[List[Any]]) } else { List(x) }) ::: flatten(xs) 

Je ne suis pas sûr, mais je pense que la raison pour laquelle le

case x: List[_] => flatten(x) ::: flatten(xs) 

fonctionne version est que il fait à la fois le contrôle et la distribution.

1

Lorsque vous faites ceci:

case x::xs => 

x est lié à la tête de la liste. Donc, si la liste est de type List[Any], la tête bien sûr est de type Any (et non List[Any])

+0

Merci Régis! – yanhan

Questions connexes