В чем разница между def foo = {} и def foo () = {} в Scala? - PullRequest
52 голосов
/ 14 сентября 2011

Учитывая следующие конструкции для определения функции в Scala, можете ли вы объяснить, в чем разница и каковы будут последствия?

def foo = {}

против

def foo() = {}

Обновление

Спасибо за быстрые ответы. Это здорово. Единственный вопрос, который остается для меня:

Если я опущу скобки, есть ли способ передать функцию? Вот что я получаю в ответе:

scala> def foo = {}
foo: Unit

scala> def baz() = {}
baz: ()Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo)
<console>:10: error: type mismatch;
 found   : Unit
 required: () => Unit
              test(foo)
                   ^

scala> test(baz)
res1: () => Unit = <function0>

Обновление 2012-09-14

Вот несколько похожих вопросов, которые я заметил:

  1. Разница между функцией с круглыми скобками и без
  2. Методы Scala без аргументов

Ответы [ 4 ]

38 голосов
/ 14 сентября 2011

Если вы включите скобки в определение, вы можете опционально опустить их при вызове метода. Если вы опустите их в определении, вы не сможете использовать их при вызове метода.

scala> def foo() {}
foo: ()Unit

scala> def bar {}
bar: Unit

scala> foo

scala> bar()
<console>:12: error: Unit does not take parameters
       bar()
          ^

Кроме того, вы можете сделать нечто подобное с вашими функциями более высокого порядка:

scala> def baz(f: () => Unit) {}
baz: (f: () => Unit)Unit

scala> def bat(f: => Unit) {}
bat: (f: => Unit)Unit

scala> baz(foo)    

scala> baz(bar)
<console>:13: error: type mismatch;
 found   : Unit
 required: () => Unit
       baz(bar)
           ^
scala> bat(foo)

scala> bat(bar)  // both ok

Здесь baz будет принимать только foo(), а не bar. Какая польза от этого, я не знаю. Но это показывает, что типы различны.

36 голосов
/ 30 сентября 2011

Позвольте мне скопировать мой ответ, который я отправил на дублированный вопрос :

Метод 0-арности в Scala может быть определен с или без скобок (). Это используется, чтобы сигнализировать пользователю о том, что метод имеет некоторый побочный эффект (например, распечатка для вывода или уничтожение данных), в отличие от того, что без, который впоследствии можно реализовать как val.

См. Программирование в Scala :

Такие беспараметрические методы довольно распространены в Scala. Напротив, методы, определенные с пустыми скобками, такие как def height (): Int, называются методами empty-paren. Рекомендуемое соглашение - использовать метод без параметров, когда нет параметров, и метод получает доступ к изменяемому состоянию только путем чтения полей содержащего объекта (в частности, он не изменяет изменяемое состояние).

Это соглашение поддерживает принцип унифицированного доступа [...]

Подводя итог, рекомендуется в стиле Scala определять методы, которые не принимают параметров и не имеют побочных эффектов, в качестве методов без параметров, то есть, оставляя пустые скобки. С другой стороны, вы никогда не должны определять метод, который имеет побочные эффекты без скобок, потому что тогда вызовы этого метода будут выглядеть как выбор поля.

4 голосов
/ 13 ноября 2015

Чтобы ответить на второй вопрос, просто добавьте _:

scala> def foo = println("foo!")
foo: Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo _)
res10: () => Unit = <function0>

scala> test(foo _)()
foo!

scala>            
0 голосов
/ 28 февраля 2018

Я бы рекомендовал всегда начинать определение с такой функции, как:

def bar {}

и только в тех случаях, когда вы вынуждены изменить его на:

def bar() {}

Причина: давайтерассмотрим эти 2 функции с точки зрения возможного использования.Как их можно вызвать И где их можно передать.

Я бы не стал называть это функцией вообще:

def bar {}

Она может быть вызвана как:

bar

но не как функция:

bar()

Мы можем использовать эту полосу, когда определяем функцию более высокого порядка с параметром call-by-name:

def bat(f: => Unit) {
    f //you must not use (), it will fail f()
}

Мы должныпомните, что => Unit - это даже не функция.Вы абсолютно не можете работать с thunk, как если бы это была функция, поскольку вы не можете рассматривать его как значение функции, которое будет храниться или передаваться.Вы можете запускать только оценки фактического выражения аргумента (любое их количество). Scala: передача функции в виде блока кода между фигурными скобками

Функция, определенная с помощью (), имеет большую область применения.Он может использоваться точно в том же контексте, что и bar:

def foo() = {}
//invokation:
foo
//or as a function:
foo()

. Он может быть передан в функцию с параметром call-by-name:

bat(foo)

Кроме того, если мы определим функцию более высокого порядка, которая принимает не параметр, определяющий имя по имени, а реальную функцию:

def baz(f: () => Unit) {}

Мы также можем передать foo в baz:

baz(foo)

Как мы видим, стандартные функции, такие как foo, имеют большую область применения.Но используя функции, определенные без () плюс определяющие функции высшего порядка, которые принимают параметр call-by-name, давайте использовать более понятный синтаксис.

Если вы не пытаетесь заархивировать лучший, более читаемый код или если вам нужна возможность передать фрагмент кода как функции, определенной с помощью параметра call-by-name, так и функции, определенной с помощьюдействительной функции, затем определите вашу функцию как стандартную:

def foo() {}

Если вы предпочитаете писать более понятный и читаемый код, а ваша функция не имеет побочных эффектов, определите функцию как:

def bar {}

PLUS попытайтесь определить функцию высшего порядка, чтобы принимать параметр call-by-name, но не функцию.Только когда вас принуждают, только в этом случае используйте предыдущую опцию.

...