Почему это «дело» необходимо? - PullRequest
4 голосов
/ 24 февраля 2011
object Test1 {
    def main(args: Array[String]) {
        val list = List("a", "b")
        list map { x ⇒ println(x) }
        list map { case x ⇒ println(x) }

        val list2 = List(("aa", "11"))
        list2 map {
            case (key, value) ⇒ println("key: "+key+", value: "+value)
        }
    }

}

Обратите внимание на последнюю строку, почему ключевое слово case должно использоваться, но list map { x ⇒ println(x) } может его удалить?

Ответы [ 5 ]

14 голосов
/ 24 февраля 2011

Вы не можете взломать кортеж в литерал функции. Вот почему вам придется использовать case, чтобы соответствовать им. Другой способ - использовать tupled , чтобы сделать вашу функцию с двумя аргументами подходящими:

import Function.tupled 
list2 map tupled {
  (key, value) => println("key: "+key+", value: "+value)
}
9 голосов
/ 24 февраля 2011
{ case (key, value) => f }

не то же самое, что

{ (key, value) => f }

Первое - это сопоставление с образцом, которое разбивает Tuple2 на его компоненты, присваивая их значения key и value. В этом случае передается только один параметр (кортеж). { x => println(x) } работает, потому что x назначается кортеж, а println печатает его.

Вторая - это функция, которая принимает два параметра и не выполняет сопоставление с образцом. Поскольку для map требуется функция, которая принимает один параметр, второй случай несовместим с map.

4 голосов
/ 24 февраля 2011

list2 имеет элементы типа Tuple2[Int, Int], поэтому сигнатура функции, которую вы должны передать map (в этом случае ... foreach - более естественный выбор, когда вы ничего не возвращаете), равна Tuple2[Int, Int] => Unit. То есть, он принимает один аргумент типа Tuple2[Int, Int].

Поскольку Tuple2 поддерживает unapply, вы можете использовать сопоставление с образцом для разделения этого кортежа в вашей функции, как вы это делали:

{
  case (key, value) ⇒ println("key: "+key+", value: "+value)
}

Подпись этой функции по-прежнему Tuple2[Int, Int] => Unit

Он идентичен и, вероятно, компилируется в те же байт-коды, что и:

{
  x: Tuple2[Int, Int] => println("key: "+x._1+", value: "+x._2)
}

Это один из многих примеров того, как Scala сочетает ортогональные концепции очень приятным образом.

3 голосов
/ 24 февраля 2011

list2 map { x => println(x) } у меня работает без проблем.Если вы хотите иметь сопоставление с образцом (разбивая ваш аргумент на части в соответствии с его структурой), вам всегда нужно case.В качестве альтернативы вы можете написать:

list2 map { x => println("key: "+x._1+", value: "+x._2) }

Кстати, map следует использовать для преобразования списка в другой.Если вы просто хотите просмотреть все элементы списка, используйте foreach или для понимания.

1 голос
/ 24 февраля 2011

Я все еще изучаю Scala, но я верю, что происходит то, что вы определили частичную функцию, принимающую один аргумент. При вызове таких методов, как List.map или List.foreach, для которых требуется только один аргумент, вы можете опустить подчеркивание или имя val.

Пример исключения имени val в закрытии:

val v = List("HEY!", "BYE!")
v.foreach { Console.println } // Pass partial function, automatically

Это то же самое, что и

val v = List("HEY!", "BYE!")
v.foreach { Console.println _ } // Pass partial function, explicitly

Использование анонимного значения:

val v = List("HEY!", "BYE!")
v.foreach { Console.println(_) } // Refer to anonymous param, explicitly

Или используя именованный val:

val v = List("HEY!", "BYE!")
v.foreach { x => Console.println(x) } // Refer to val, explicitly

В вашем замыкании вы используете частичную функцию (оператор case), которая принимает анонимную переменную и немедленно превращает ее в кортеж, связанный с двумя отдельными переменными.

Полагаю, я обманываю один из фрагментов выше. Когда я доберусь до своего рабочего компьютера, я проверю в REPL.

Кроме того, взгляните на Функция Curry в Scala для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...