Отображение функции Scala с необязательным параметром - PullRequest
5 голосов
/ 05 апреля 2011

У меня проблемы с отображением функции, которая принимает необязательный параметр.Я получаю такую ​​же ошибку типа, как если бы параметр не был необязательным.Вот простая иллюстрация:

scala> def multiple(m: Int, n: Int = 2) = m * n
multiple: (m: Int,n: Int)Int

scala> multiple(5)
res0: Int = 10

scala> multiple(5, 7)
res1: Int = 35

scala> (1 to 10).map(multiple)
<console>:7: error: type mismatch;
 found   : (Int, Int) => Int
 required: (Int) => ?
       (1 to 10).map(multiple)

Вот один из способов заставить его работать, но он требует повторения аргумента по умолчанию, который является кошмаром обслуживания:

scala> (1 to 5).map { n => multiple(n, 2) } 
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

Есть ли лучший способсделать это?В более общем смысле, почему функция с необязательным параметром имеет такой же тип, как если бы параметр не был необязательным?Каков фактический тип multiple?

Ответы [ 4 ]

12 голосов
/ 05 апреля 2011

Это похоже на работу:

(1 to 10).map(multiple(_)) 

//res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
5 голосов
/ 07 апреля 2011

При использовании в ситуации, когда ожидается функция, Scala «поднимет» метод до FunctionN [T1, ..., R].

В этой ситуации, так как множественный принимает 2 параметра, он эффективно поднимается как:

(1 to 10).map(new Function2[Int,Int,Int]{ def apply(v1: Int, v2: Int) = multiple(v1, v2) })

Даже если исходный метод имеет аргумент по умолчанию, объекты FunctionN - нет. Ошибка типа теперь должна быть понятна здесь. Когда используется множественное число (_), это вызов множественного числа с одним аргументом со вторым значением по умолчанию, поэтому он обрабатывается следующим образом:

(1 to 10).map(new Function1[Int,Int]{ def apply(v1: Int) = multiple(v1) })

Этот тип проверяет нормально, как показали другие.

Обратите внимание, что (несколько _) не совпадает с несколькими (_). Первый представляет множественное число со всеми аргументами, помеченными подстановочными символами, и поэтому является Function2, в то время как последний применяет множественное число к одному аргументу с подстановочными знаками, в результате чего другой аргумент будет установлен по умолчанию в этой точке , как и Function1. .

Значения по умолчанию применяются во время компиляции путем введения нового метода, который возвращает значение по умолчанию. Если вызывается метод по умолчанию, если аргументы отсутствуют, компилятор добавит необходимые вызовы к дополнительным методам для параметров по умолчанию перед добавлением вызова к самому методу. Это означает, что сам метод компилируется в код, который сам не знает параметров по умолчанию. Чтобы увидеть это, скомпилируйте следующий пример класса:

class Defaults {
  def m(a: Int, b: Int = 3) = a * b
  def a = m(1)
  def b = m(1, 2)
}

затем запустите: javap -c По умолчанию

1 голос
/ 05 апреля 2011

За возможность писать

scala> (1 to 10).map(multiple)

Вы можете передать частично примененную функцию

def multiple(m: Int, n: Int) = m * n
val mul2 = multiple(_: Int, 2)
(1 to 10) map mul2
0 голосов
/ 05 апреля 2011

Вот один из способов заставить его работать, но это требует повторения по умолчанию аргумент, который является поддержанием кошмар:

Кстати, это тоже работает:

scala> (1 to 5).map { n => multiple(n) } 
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

Так что вам не нужно повторять аргумент по умолчанию;) [Scala 2.9.0.RC1]

...