web-dev-qa-db-fra.com

Que signifie param: _ * dans Scala?

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

val eventQueue = Queue(events)

Pour une raison quelconque, les travaux suivants:

val eventQueue = Queue(events : _*)

Mais je voudrais comprendre ce qu'il fait et pourquoi cela fonctionne? J'ai déjà regardé la signature du Queue.apply une fonction:

def apply[A](elems: A*)

Et je comprends pourquoi la première tentative ne fonctionne pas, mais quelle est la signification de la seconde? Quel est :, et _* dans ce cas, et pourquoi la fonction apply ne prend-elle pas simplement un Iterable[A]?

66
Chris

a: A est une attribution de type; voir Quel est le but des attributions de type dans Scala?

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

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

72
Ben James

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

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 de langue, "Paramètres répétés".

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

67

Pour Python les gens:

Scala's _* L'opérateur est plus ou moins l'équivalent de Python * - opérateur .


Exemple

Conversion de l'exemple scala à partir de lien fourni par Luigi Plinge :

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

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

à Python ressemblerait à:

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

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

et les deux donnent la sortie suivante:

Qu'est-ce que
up
doc?


La différence: décompresser les paramètres positionnels

Alors que Python *- L'opérateur peut également gérer le déballage des paramètres positionnels/paramètres pour les fonctions à aire fixe:

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

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

8

Faire de même avec Scala:

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

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

échouera:

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

Mais il est possible d'obtenir la même chose avec scala:

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

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

Selon 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é. Cela fonctionne comme un mécanisme pour saisir l'objet fonction. tupled renvoie une nouvelle fonction qui de arity-1 qui prend un seul tuple arity-n.

Lecture ultérieure:

2
Murmel