Подчеркивание и конкатенация строк в List.map с Scala
Scala позволяет использовать подчеркивание для создания простой карты. Так, например, вместо того, чтобы писать:
def roleCall(people: String*){
people.toList.map(x => println(x))
}
... вместо этого я могу написать:
def roleCall(people: String*){
people.toList.map(println(_))
}
Однако по какой-то причине я не могу написать:
def greet(people: String*){
// This won't compile!
people.toList.map(println("Hello " + _))
}
вместо этого я должен написать:
def greet(people: String*){
people.toList.map(x => println("Hello " + x))
}
Кто-нибудь может объяснить почему?
1 ответ
По сути, сокращенный синтаксис для определений функций работает, как и ожидалось, только если нет вложенных скобок. Это потому, что каждый уровень вложенности создает свою собственную область, в которой живут подчеркивания. В REPL вы можете проверить, например, что:
scala> val list = List(1,2,3).map(_ + 1)
list: List[Int] = List(2, 3, 4)
а также
scala> val list = List(1,2,3).map((_ + 1))
list: List[Int] = List(2, 3, 4)
оба работают, но как только вы добавите что-нибудь после скобок, вы получите ошибку:
val list = List(1,2,3).map((_ + 1) + 1)
<console>:58: error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
val list = List(1,2,3).map((_ + 1) + 1)
Как видите, ошибка относится только к функции (_ + 1) (показана как ((x$1) => x$1.$plus(1))
в сообщении), а не ко всему выражению (_ + 1) + 1
поэтому часть в скобках рассматривается как отдельная функция и подчеркивание _
интерпретируется в рамках этой внутренней функции, а не внешней.
Я не совсем уверен, почему List(1,2,3).map(println(_))
работает, но, похоже, это некий крайний случай, который из-за единственного аргумента, кажется, просто работает по простому совпадению. Я был бы рад сам узнать подробности. В любом случае, использование скобок внутри определений анонимных функций с подчеркиванием неизбежно вызовет проблемы рано или поздно, и их лучше избегать.