118 votes

Que signifie param : _* en Scala ?

Étant nouveau à Scala (2.9.1), j'ai un problème de List[Event] et souhaite le copier dans un Queue[Event] mais la syntaxe suivante donne un Queue[List[Event]] au lieu de cela :

val eventQueue = Queue(events)

Pour une raison quelconque, la procédure suivante fonctionne :

val eventQueue = Queue(events : _*)

Mais j'aimerais comprendre ce qu'il fait et pourquoi il fonctionne. J'ai déjà regardé la signature de la fonction Queue.apply fonction :

def apply[A](elems: A*)

Je comprends pourquoi la première tentative ne fonctionne pas, mais quel est le sens de la seconde ? Qu'est-ce que : et _* dans ce cas, et pourquoi le apply prend simplement un Iterable[A] ?

114voto

Ben James Points 41165

a: A est une ascription de type ; voir A quoi servent les descriptions de type en Scala ?

: _* est une instance spéciale d'ascription de type qui indique au compilateur de traiter un argument unique d'un type de séquence comme une séquence d'arguments variables, c'est-à-dire varargs.

Il est tout à fait possible de créer un Queue en utilisant Queue.apply qui a un seul élément qui est une séquence ou un itérable, donc c'est exactement ce qui se passe quand vous donnez un seul Iterable[A] .

100voto

Luigi Plinge Points 23552

Il s'agit d'une notation spéciale qui indique au compilateur de passer chaque élément comme son propre argument, plutôt que l'ensemble des éléments comme un seul argument. Voir aquí .

Il s'agit d'une annotation de type qui indique un argument de séquence et est mentionnée comme une "exception" à la règle générale dans la section 4.6.2 des spécifications du langage, "Paramètres répétés".

Elle est utile lorsqu'une fonction prend un nombre variable d'arguments, par exemple une fonction telle que def sum(args: Int*) qui peut être invoquée comme suit sum(1) , sum(1,2) etc. Si vous disposez d'une liste telle que xs = List(1,2,3) vous ne pouvez pas passer xs lui-même, car il s'agit d'un List plutôt qu'un Int mais vous pouvez passer ses éléments en utilisant sum(xs: _*) .

20voto

user1885518 Points 495

Pour les utilisateurs de Python :

Le système _* est plus ou moins l'équivalent de l'opérateur *-opérateur .


Exemple

Conversion de l'exemple scala de la base de données lien fourni par Luigi Plinge :

def echo(args: String*) = 
    for (arg <- args) println(arg)

val arr = Array("What's", "up", "doc?")
echo(arr: _*)

en Python ressemblerait à ce qui suit :

def echo(*args):
    for arg in args:
        print "%s" % arg

arr = ["What's", "up", "doc?"]
echo(*arr)

et tous deux donnent le résultat suivant :

Qu'est-ce que
monter
doc ?


La différence : le décodage des paramètres de position

Alors que la fonction * -L'opérateur peut également traiter le déballage des paramètres positionnels/paramètres pour les fonctions à polarité fixe :

def multiply (x, y):
    return x * y

operands = (2, 4)
multiply(*operands)

8

Faire la même chose avec Scala :

def multiply(x:Int, y:Int) = {
    x * y;
}

val operands = (2, 4)
multiply (operands : _*)

échouera :

pas assez d'arguments pour la méthode multiplier : (x : Int, y : Int)Int.
Paramètre de valeur non spécifiée y.

Mais il est possible de faire la même chose avec scala :

def multiply(x:Int, y:Int) = {
    x*y;
}

val operands = (2, 4)
multiply _ tupled operands

Selon le Lorrin Nelson voici comment cela fonctionne :

La première partie, f _, est la syntaxe d'une fonction partiellement appliquée dans laquelle aucun des arguments n'a été spécifié. Il s'agit d'un mécanisme permettant d'obtenir l'objet fonction. tupled renvoie une nouvelle fonction d'arité-1 qui prend un seul tuple d'arité-n.

Autres lectures :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X