Даны три способа выражения одной и той же функции f(a) := a + 1:

val f1 = (a:Int) => a + 1
def f2 = (a:Int) => a + 1
def f3:(Int => Int) = a => a + 1

Чем отличаются эти определения? REPL не указывает очевидных различий:

scala> f1
res38: (Int) => Int = <function1>
scala> f2
res39: (Int) => Int = <function1>
scala> f3
res40: (Int) => Int = <function1>
92
qrest 5 Сен 2010 в 20:14
11
Следует отметить, что во втором блоке выше, оценка f1 в REPL показывает значение, статически связанное с f1, в то время как оценка f2 и f3 показывает результат вызывая эти методы. В частности, новый экземпляр Function1[Int, Int] создается каждый раз при вызове f2 или f3, а f1 остается неизменным Function1[Int, Int] навсегда.
 – 
Randall Schulz
5 Сен 2010 в 23:12
Учитывая, что версия val не требует нового экземпляра функции, зачем в этом случае использовать def?
 – 
virtualeyes
1 Июн 2012 в 18:04
2
Единственная ситуация, которую я могу вспомнить, когда можно увидеть defs, дающие значения FunctionN [...], - это библиотека синтаксического анализатора комбинатора. Не очень распространено писать методы, которые дают функции, и практически никогда нельзя использовать def для получения множества копий семантически / функционально неизменной функции.
 – 
Randall Schulz
5 Июн 2012 в 04:18

3 ответа

Лучший ответ

f1 - это функция, которая принимает целое число и возвращает целое число.

f2 - это метод с нулевой арностью, который возвращает функцию, которая принимает целое число и возвращает целое число. (Когда вы позже набираете f2 в REPL, он становится вызовом метода f2.)

f3 совпадает с f2. Вы просто не используете здесь вывод типов.

112
missingfaktor 16 Сен 2010 в 07:30
6
Почему f1 - это function, а f2 - это method?
 – 
Freewind
7 Май 2013 в 07:13
17
@Freewind, функция - это объект с методом с именем apply. Метод, в общем, метод.
 – 
missingfaktor
7 Май 2013 в 22:10
Отличный ответ. Вопрос: вы говорите, что f2 имеет нулевую арность, но разве она не унарна? en.wikipedia.org/wiki/Arity "Функция с нулевым значением не принимает аргументов. Унарная функция принимает один аргумент ". Просто любопытно!
 – 
Matthew Cornell
7 Янв 2015 в 03:38
5
@MatthewCornell, f2 сам по себе не принимает аргументов. Функциональный объект, который он возвращает, выполняет.
 – 
missingfaktor
8 Янв 2015 в 10:45

Внутри класса val оценивается при инициализации, в то время как def оценивается только тогда, и каждый раз , вызывается функция. В приведенном ниже коде вы увидите, что x оценивается при первом использовании объекта, но не снова при доступе к члену x. Напротив, y не оценивается при создании экземпляра объекта, но оценивается каждый раз, когда к члену обращаются.

  class A(a: Int) {
    val x = { println("x is set to something"); a }
    def y = { println("y is set to something"); a }
  }

  // Prints: x is set to something
  val a = new A(1)

  // Prints: "1"
  println(a.x)

  // Prints: "1"                               
  println(a.x)

  // Prints: "y is set to something" and "1"                                  
  println(a.y)

  // Prints: "y is set to something" and "1"                                                                                   
  println(a.y)
122
karmakaze 16 Янв 2014 в 02:09
Это правда только внутри класса?
 – 
Andrew Cassidy
26 Авг 2014 в 20:58
Например: scala> var b = 5 b: Int = 5 scala> val a: (Int => Int) = x => x + ba: Int => Int = scala> a (5) res48: Int = 10 scala> b = 6 b: Int = 6 scala> a (5) res49: Int = 11 Я ожидал, что a (5) вернет 10, а значение b будет встроено
 – 
Andrew Cassidy
26 Авг 2014 в 20:59
Функция a неизменяема и вычисляется при инициализации, но b остается изменяемым значением. Таким образом, ссылка на b устанавливается во время инициализации, но значение, хранимое b, остается изменяемым. Ради интереса теперь вы можете создать новый val b = 123. После этого ваш a(5) всегда будет давать 11, поскольку b теперь является совершенно новым значением.
 – 
Jack
28 Авг 2014 в 09:57
Спасибо ... в этом есть смысл. Это совпадает с определением «лексической области видимости», поскольку функция a содержит ссылку на исходную «var b». Я думаю, что меня сбило с толку то, что говорят: var b = 5; val c = b; b = 6; действует иначе. Думаю, мне не следует ожидать, что определение функции, содержащее ссылки на исходную «лексическую» область видимости, будет вести себя так же, как Int.
 – 
Andrew Cassidy
28 Авг 2014 в 17:49

Выполнение определения, такого как def x = e, не приведет к оценке выражения e . Вместо этого e оценивается всякий раз, когда используется x . В качестве альтернативы Scala предлагает определение значения val x = e, который оценивает правую часть e как часть оценки определения. Если затем используется x , он немедленно заменяется на предварительно вычисленное значение e , так что выражение не нужно вычислять снова.

Scala на примере Автор: Мартин Одерски

3
Alexander 10 Мар 2016 в 15:32