Распаковка параметров
Допустим есть список кортежей, например:
val xs: List[(Int, Int)] = List((1, 2), (3, 4))
и необходимо изменить xs
в List[Int]
, чтобы каждая пара чисел была сопоставлена с их суммой.
Ранее лучший способ сделать это - с помощью декомпозиции сопоставления с образцом:
xs map {
case (x, y) => x + y
}
Хотя это правильно, это также неудобно и сбивает с толку, поскольку case
предполагает,
что сопоставление с образцом может завершиться ошибкой.
Как более короткая и понятная альтернатива, Scala 3 теперь позволяет
xs.map {
(x, y) => x + y
}
// res0: List[Int] = List(3, 7)
или, что то же самое:
xs.map(_ + _)
// res1: List[Int] = List(3, 7)
а также
def combine(i: Int, j: Int) = i + j
xs.map(combine)
// res2: List[Int] = List(3, 7)
Как правило, значение функции с n > 1
параметрами упаковывается в функциональный тип
формы ((T_1, ..., T_n)) => U
, если это ожидаемый тип.
Параметр кортежа декомпозируется, и его элементы передаются непосредственно базовой функции.
Более конкретно, адаптация применяется к несовпадающему списку формальных параметров. В частности, адаптация не является преобразованием между типами функций. Поэтому не принимается:
val combiner: (Int, Int) => Int = _ + _
xs.map(combiner)
// error:
// Found: (repl.MdocSession.MdocApp.combiner : (Int, Int) => Int)
// Required: ((Int, Int)) => Nothing
// xs.map(combiner)
// ^^^^^^^^
Значение функции должно быть явно сложены:
xs.map(combiner.tupled)
// res4: List[Int] = List(3, 7)
Преобразование может быть предусмотрено в пользовательском коде:
import scala.language.implicitConversions
transparent inline implicit def `fallback untupling`(f: (Int, Int) => Int): ((Int, Int)) => Int =
p => f(p._1, p._2) // use specialized apply instead of unspecialized `tupled`
xs.map(combiner)
Попытка распаковки параметров предпринимается до применения преобразований, поэтому преобразование области действия не может нарушить распаковку.
Ссылки: