Ceci :
"Hello" foreach (x = x * _.toLong)
est en fait développé par le compilateur en ceci :
"Hello" foreach (x = x * (x$1 => x$1.toLong))
De toute évidence, la multiplication d'un Long
avec une fonction anonyme qui invoque toLong()
sur son argument n'a pas beaucoup de sens. Bien sûr, écrire soi-même la version expansive fonctionne bien, par exemple "Hello" foreach (y => x = x * y.toLong)
.
Dans votre deuxième expression "Hello" foreach (x *= _.toLong )
il y a deux expansions qui doivent être faites par le compilateur : une qui expanse le trait de soulignement comme dans l'exemple précédent et une qui expanse x *= y
en x = x * y
. Évidemment, le premier se produit avant le second, donc le compilateur voit (x *= _.toLong)
comme une expression unique. Ainsi, au lieu de se développer en (x *= (x$1 => x$1.toLong))
il s'étend à x$1 => (x *= x$1.toLong)
. Je ne peux pas vraiment pointer du doigt car il faudrait que je creuse dans les spécifications de Scala et les internes du compilateur, mais maintenant vous avez une idée de ce qui cause ce comportement.
Mon conseil personnel est d'utiliser le trait de soulignement uniquement dans des situations triviales, telles que List(1, 2, 3).map(_.toLong)
et, dans des situations comme la vôtre, écrivez toujours la fonction complète, par ex. "Hello" foreach (arg => x = x * arg.toLong)
.
Notez également que l'utilisation d'effets secondaires et de valeurs mutables est un gros non-sens en Scala. Voici une version améliorée de votre code :
val result = "Hello".foldLeft(1: Long)((x, c) => x * c.toLong)