Что означает param: _ * в Scala? - PullRequest
       7

Что означает param: _ * в Scala?

63 голосов
/ 29 октября 2011

Будучи новичком в Scala (2.9.1), у меня есть List[Event], и я хотел бы скопировать его в Queue[Event], но следующий синтаксис дает вместо Queue[List[Event]]:

val eventQueue = Queue(events)

По какой-то причине работает следующее:

val eventQueue = Queue(events : _*)

Но я бы хотел понять, что он делает и почему он работает?Я уже посмотрел на сигнатуру функции Queue.apply:

def apply[A](elems: A*)

И я понимаю, почему первая попытка не работает, но в чем смысл второй?Что такое : и _* в этом случае, и почему функция apply не принимает Iterable[A]?

Ответы [ 3 ]

69 голосов
/ 29 октября 2011

a: A - тип надписи;см. Какова цель атрибутов типа в Scala?

: _* - это особый экземпляр атрибута типа, который указывает компилятору обрабатывать один аргумент типа последовательности как переменный аргумент.sequence, то есть varargs.

Совершенно верно создать Queue, используя Queue.apply, который имеет единственный элемент, который является последовательностью или итерируемым, так что именно это происходит, когда вы даете один Iterable[A].

66 голосов
/ 29 октября 2011

Это специальная запись, которая указывает компилятору передавать каждый элемент как его собственный аргумент, а не все как один аргумент.См. здесь .

Это аннотация типа, которая указывает аргумент последовательности и упоминается как «исключение» из общего правила в разделе 4.6.2спецификация языка, «Повторяющиеся параметры».

Это полезно, когда функция принимает переменное число аргументов, например, такую ​​функцию, как def sum(args: Int*), которая может быть вызвана как sum(1), sum(1,2) и т. д.Если у вас есть список, такой как xs = List(1,2,3), вы не можете передать сам xs, потому что это List, а не Int, но вы можете передать его элементы, используя sum(xs: _*).

2 голосов
/ 12 января 2018

Для людей Python:

Оператор Scala _* более или менее эквивалентен * оператора Python - .


Пример

Преобразование примера scala по ссылке , предоставленной Луиджи Плинге :

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

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

для Python будет выглядеть так:

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

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

и оба дают следующий вывод:

Что
до
док?


Разница: распаковка позиционных параметров

Оператор Python * может также распаковывать позиционные параметры / параметры для функций с фиксированной арностью:

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

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

8

То же самое со Scala:

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

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

потерпит неудачу:

недостаточно аргументов для умножения метода: (x: Int, y: Int) Int.
Не указано значение параметра y.

Но можно добиться того же с помощью scala:

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

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

Согласно Лоррин Нельсон вот как это работает:

Первая часть, f _, представляет собой синтаксис частично примененной функции, в которой не указан ни один из аргументов. Это работает как механизм для захвата объекта функции. tupled возвращает новую функцию arity-1, которая принимает один кортеж arity-n.

Дальнейшее чтение:

...