Привет, что Int => Booleanзначит? Я думаю, что синтаксис определенияdef foo(bar: Baz): Bin = expr
Ziu
@Ziu означает, что функция 'even' получает Int в качестве аргумента и возвращает логическое значение в качестве типа значения. Таким образом, вы можете назвать 'even (3)', который оценивает как логическое значение 'false'
Денис Лобур,
@DenysLobur спасибо за ваш ответ! Любая ссылка об этом синтаксисе?
Зиу
@Ziu Я в основном узнал об этом из курса Coursera Одерского - coursera.org/learn/progfun1 . К тому времени, когда вы закончите, вы поймете, что означает «Type => Type»
Денис Лобур
Ответы:
326
Метод def evenоценивает по вызову и каждый раз создает новую функцию (новый экземпляр Function1).
def even:Int=>Boolean= _ %2==0
even eq even//Boolean = falseval even:Int=>Boolean= _ %2==0
even eq even//Boolean = true
С помощью defвы можете получить новую функцию при каждом вызове:
val test:()=>Int={val r = util.Random.nextInt()=> r}
test()// Int = -1049057402
test()// Int = -1049057402 - same resultdef test:()=>Int={val r = util.Random.nextInt()=> r}
test()// Int = -240885810
test()// Int = -1002157461 - new result
valоценивает когда определено, def- когда вызвано:
scala>val even:Int=>Boolean=???
scala.NotImplementedError: an implementation is missing
scala>def even:Int=>Boolean=???
even:Int=>Boolean
scala> even
scala.NotImplementedError: an implementation is missing
Обратите внимание , что есть третий вариант: lazy val.
Он оценивается при первом вызове:
scala>lazyval even:Int=>Boolean=???
even:Int=>Boolean=<lazy>
scala> even
scala.NotImplementedError: an implementation is missing
Но FunctionNкаждый раз возвращает один и тот же результат (в данном случае один и тот же ):
lazyval even:Int=>Boolean= _ %2==0
even eq even//Boolean = truelazyval test:()=>Int={val r = util.Random.nextInt()=> r}
test()// Int = -1068569869
test()// Int = -1068569869 - same result
Производительность
val оценивает когда определено.
defоценивается при каждом вызове, поэтому производительность может быть хуже, чем valпри нескольких вызовах. Вы получите ту же производительность за один звонок. И без вызовов вы не получите никаких накладных расходов def, так что вы можете определить его, даже если вы не будете использовать его в некоторых ветвях.
С помощью a lazy valвы получите ленивую оценку: вы можете определить ее, даже если вы не будете использовать ее в некоторых ветвях, и она будет оцениваться один или никогда, но вы получите небольшие издержки от двойной проверки блокировки при каждом доступе к вашему lazy val.
Как заметил @SargeBorsch, вы можете определить метод, и это самый быстрый вариант:
def even(i:Int):Boolean= i %2==0
Но если вам нужна функция (не метод) для композиции функций или для функций более высокого порядка (например filter(even)), компилятор будет генерировать функцию из вашего метода каждый раз, когда вы используете ее как функцию, поэтому производительность может быть несколько хуже, чем с val.
Не могли бы вы сравнить их по производительности? Разве не важно оценивать функцию каждый раз, когда evenвызывается.
Амир Карими
2
defможет использоваться для определения метода, и это самый быстрый вариант. @ A.Karimi
Отображаемое имя
2
Для прикола: на 2.12 even eq even.
Сом-Снитт
Есть ли концепция встроенных функций, как в C ++? Я из мира C ++, так что извините за мое невежество.
animageofmine
2
@animageofmine Scala-компилятор может попытаться встроить методы. Есть @inlineатрибут для этого. Но он не может встроить функции, потому что вызов функции - это вызов виртуального applyметода объекта функции. В некоторых ситуациях JVM может девиртуализировать и включать такие вызовы, но не в целом.
сен
24
Учти это:
scala>def even:(Int=>Boolean)={
println("def");(x => x %2==0)}
even:Int=>Boolean
scala>val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}val//gets printed while declaration. line-4
even2:Int=>Boolean=<function1>
scala> even(1)def
res9:Boolean=false
scala> even2(1)
res10:Boolean=false
Вы видите разницу? Коротко:
def : для каждого вызова evenон evenснова вызывает тело метода. Но с even2ie val функция инициализируется только один раз при объявлении (и, следовательно, она печатается valв строке 4 и больше никогда), и каждый раз при обращении к ней используется один и тот же вывод. Например попробуйте сделать это:
scala>import scala.util.Randomimport scala.util.Random
scala>val x ={Random.nextInt }
x:Int=-1307706866
scala> x
res0:Int=-1307706866
scala> x
res1:Int=-1307706866
Когда xинициализируется, возвращаемое значение Random.nextIntустанавливается как окончательное значение x. При следующем xиспользовании снова будет всегда возвращаться одно и то же значение.
Вы также можете лениво инициализировать x. т.е. когда он используется первый раз, он инициализируется, а не при объявлении. Например:
scala>lazyval y ={Random.nextInt }
y:Int=<lazy>
scala> y
res4:Int=323930673
scala> y
res5:Int=323930673
Я думаю, что ваше объяснение может подразумевать то, что вы не намерены. Попробуйте позвонить even2дважды, один раз с 1и один раз с 2. Вы получите разные ответы на каждый звонок. Таким образом, хотя при printlnпоследующих вызовах функция не выполняется, вы не получите одинаковый результат от разных вызовов even2. Что касается того, почему printlnне выполняется снова, это другой вопрос.
Мелстон
1
это на самом деле очень интересно. Как и в случае с val, то есть даже с 2, значение val оценивается как параметризованное значение. так что да с val вы оценки функции, ее значение. Println не является частью оцененного значения. Это часть оценки, но не оцененная стоимость. Хитрость здесь в том, что оценочное значение на самом деле является параметризованным значением, которое зависит от некоторого ввода. умная вещь
MaatDeamon
1
@ Melston точно! это то, что я понял, так почему же println не выполняется снова, пока вывод изменяется?
Aur
1
@aur, что возвращает even2, на самом деле является функцией (выражение в скобках в конце определения even2). Эта функция фактически вызывается с параметром, который вы передаете в even2 каждый раз, когда вызываете ее.
Мелстон
5
Посмотри это:
var x =2// using var as I need to change it to 3 laterval sq = x*x // evaluates right now
x =3// no effect! sq is already evaluated
println(sq)
Удивительно, но это напечатает 4, а не 9! val (даже var) оценивается немедленно и присваивается.
Теперь измените val на def .. он напечатает 9! Def - это вызов функции. Он будет оценивать каждый раз, когда вызывается.
val т.е. "sq" по определению Scala является фиксированным. Он оценивается прямо во время объявления, вы не можете изменить позже. В других примерах, где even2 также val, но он объявлен с сигнатурой функции, т. Е. "(Int => Boolean)", поэтому это не тип Int. Это функция, и ее значение устанавливается следующим выражением
{
println("val");(x => x %2==0)}
Согласно свойству Scala val, вы не можете назначить другую функцию even2, такое же правило, как sq.
О том, почему вызов функции eval2 val не выдает «val» снова и снова?
Исходный код:
val even2:(Int=>Boolean)={
println("val");(x => x %2==0)}
Мы знаем, что в Scala последнее выражение вышеприведенного вида выражения (внутри {..}) фактически возвращается в левую часть. Таким образом, вы заканчиваете тем, что устанавливаете even2 в функцию «x => x% 2 == 0», которая соответствует типу, который вы объявили для типа Even2 val, т.е. (Int => Boolean), так что компилятор доволен. Теперь even2 указывает только на функцию «(x => x% 2 == 0)» (а не на любые другие операторы ранее, например println («val») и т. Д. Вызов события 2 с другими параметрами фактически вызовет «(x => x% 2»). == 0) "код, так как только он сохраняется с помощью event2.
Выполнение определения, такого как def x = e, не будет оценивать выражение e. Вместо этого оценивается каждый раз, когда вызывается x.
В качестве альтернативы, Scala предлагает определение значения
val x = e, которое оценивает правую часть как часть оценки определения. Если затем затем используется x, он немедленно заменяется предварительно вычисленным значением e, так что выражение не нужно вычислять снова.
также, Val является оценкой по значению. Это означает, что выражение правой части оценивается во время определения. Где Def по оценке имени. Он не будет оцениваться, пока не будет использован.
В дополнение к вышеупомянутым полезным ответам, мои выводы:
def test1:Int=>Int={
x => x
}--test1: test1[]=>Int=>Intdef test2():Int=>Int={
x => x+1}--test2: test2[]()=>Int=>Intdef test3():Int=4--test3: test3[]()=>Int
Выше показано, что «def» - это метод (с нулевыми параметрами аргумента), который возвращает другую функцию «Int => Int» при вызове.
С таким старым вопросом и с таким количеством уже отправленных ответов часто бывает полезно объяснить, чем ваш ответ отличается или дополняет информацию, представленную в существующих ответах.
Int => Boolean
значит? Я думаю, что синтаксис определенияdef foo(bar: Baz): Bin = expr
Ответы:
Метод
def even
оценивает по вызову и каждый раз создает новую функцию (новый экземплярFunction1
).С помощью
def
вы можете получить новую функцию при каждом вызове:val
оценивает когда определено,def
- когда вызвано:Обратите внимание , что есть третий вариант:
lazy val
.Он оценивается при первом вызове:
Но
FunctionN
каждый раз возвращает один и тот же результат (в данном случае один и тот же ):Производительность
val
оценивает когда определено.def
оценивается при каждом вызове, поэтому производительность может быть хуже, чемval
при нескольких вызовах. Вы получите ту же производительность за один звонок. И без вызовов вы не получите никаких накладных расходовdef
, так что вы можете определить его, даже если вы не будете использовать его в некоторых ветвях.С помощью a
lazy val
вы получите ленивую оценку: вы можете определить ее, даже если вы не будете использовать ее в некоторых ветвях, и она будет оцениваться один или никогда, но вы получите небольшие издержки от двойной проверки блокировки при каждом доступе к вашемуlazy val
.Как заметил @SargeBorsch, вы можете определить метод, и это самый быстрый вариант:
Но если вам нужна функция (не метод) для композиции функций или для функций более высокого порядка (например
filter(even)
), компилятор будет генерировать функцию из вашего метода каждый раз, когда вы используете ее как функцию, поэтому производительность может быть несколько хуже, чем сval
.источник
even
вызывается.def
может использоваться для определения метода, и это самый быстрый вариант. @ A.Karimieven eq even
.@inline
атрибут для этого. Но он не может встроить функции, потому что вызов функции - это вызов виртуальногоapply
метода объекта функции. В некоторых ситуациях JVM может девиртуализировать и включать такие вызовы, но не в целом.Учти это:
Вы видите разницу? Коротко:
def : для каждого вызова
even
онeven
снова вызывает тело метода. Но сeven2
ie val функция инициализируется только один раз при объявлении (и, следовательно, она печатаетсяval
в строке 4 и больше никогда), и каждый раз при обращении к ней используется один и тот же вывод. Например попробуйте сделать это:Когда
x
инициализируется, возвращаемое значениеRandom.nextInt
устанавливается как окончательное значениеx
. При следующемx
использовании снова будет всегда возвращаться одно и то же значение.Вы также можете лениво инициализировать
x
. т.е. когда он используется первый раз, он инициализируется, а не при объявлении. Например:источник
even2
дважды, один раз с1
и один раз с2
. Вы получите разные ответы на каждый звонок. Таким образом, хотя приprintln
последующих вызовах функция не выполняется, вы не получите одинаковый результат от разных вызововeven2
. Что касается того, почемуprintln
не выполняется снова, это другой вопрос.Посмотри это:
Удивительно, но это напечатает 4, а не 9! val (даже var) оценивается немедленно и присваивается.
Теперь измените val на def .. он напечатает 9! Def - это вызов функции. Он будет оценивать каждый раз, когда вызывается.
источник
val т.е. "sq" по определению Scala является фиксированным. Он оценивается прямо во время объявления, вы не можете изменить позже. В других примерах, где even2 также val, но он объявлен с сигнатурой функции, т. Е. "(Int => Boolean)", поэтому это не тип Int. Это функция, и ее значение устанавливается следующим выражением
Согласно свойству Scala val, вы не можете назначить другую функцию even2, такое же правило, как sq.
О том, почему вызов функции eval2 val не выдает «val» снова и снова?
Исходный код:
Мы знаем, что в Scala последнее выражение вышеприведенного вида выражения (внутри {..}) фактически возвращается в левую часть. Таким образом, вы заканчиваете тем, что устанавливаете even2 в функцию «x => x% 2 == 0», которая соответствует типу, который вы объявили для типа Even2 val, т.е. (Int => Boolean), так что компилятор доволен. Теперь even2 указывает только на функцию «(x => x% 2 == 0)» (а не на любые другие операторы ранее, например println («val») и т. Д. Вызов события 2 с другими параметрами фактически вызовет «(x => x% 2»). == 0) "код, так как только он сохраняется с помощью event2.
Просто чтобы прояснить это подробнее, ниже приведена другая версия кода.
Что случится ? здесь мы видим, что «внутри финального fn» печатается снова и снова, когда вы вызываете even2 ().
источник
Выполнение определения, такого как
def x = e
, не будет оценивать выражение e. Вместо этого оценивается каждый раз, когда вызывается x.В качестве альтернативы, Scala предлагает определение значения
val x = e
, которое оценивает правую часть как часть оценки определения. Если затем затем используется x, он немедленно заменяется предварительно вычисленным значением e, так что выражение не нужно вычислять снова.источник
также, Val является оценкой по значению. Это означает, что выражение правой части оценивается во время определения. Где Def по оценке имени. Он не будет оцениваться, пока не будет использован.
источник
В дополнение к вышеупомянутым полезным ответам, мои выводы:
Выше показано, что «def» - это метод (с нулевыми параметрами аргумента), который возвращает другую функцию «Int => Int» при вызове.
Преобразование методов в функции хорошо объяснено здесь: https://tpolecat.github.io/2014/06/09/methods-functions.html
источник
В REPL,
def означает
call-by-name
, оценивается по требованиюval означает
call-by-value
, оценивается при инициализацииисточник