Какова разница между:
scala> def foo = 5
foo: Int
и
scala> def foo() = 5
foo: ()Int
Кажется, что в обоих случаях В итоге я получаю переменную foo
, на которую могу ссылаться без скобок, всегда получая значение 5
.
В любом случае вы не определяете переменную. Вы определяете метод. Первый метод не имеет списков параметров, второй имеет один пустой список параметров. Первый из них должен быть вызывается так
val x = foo
, а второй должен вызываться так
val x = foo()
. Однако компилятор Scala позволит вам вызывать методы с одним пустым списком параметров без скобок, поэтому для второго метода будет работать любая форма вызова. Методы без списков параметров не могут быть вызваны с круглыми скобками
. Предпочтительный стиль Scala состоит в том, чтобы определять и вызывать методы без аргументов, которые имеют побочные эффекты в круглых скобках. Методы без аргументов без побочных эффектов следует определять и вызывать без скобок.
Если вы на самом деле определяете переменную, синтаксис следующий:
val foo = 5
Прежде чем что-либо сказать, def
не определяет поле, а определяет метод.
Во втором случае вы можете опустить круглые скобки из-за специфической особенности Scala. Здесь есть два интересных отличия: механическое и рекомендуемое использование.
Начиная с последнего, рекомендуется использовать пустой список параметров при наличии побочных эффектов. Классический пример - close ()
. Вы должны опустить круглые скобки, если нет побочных эффектов при вызове элемента.
Теперь, в качестве практического различия - помимо возможных странных синтаксических ошибок в угловых случаях (я не говорю, что они есть, просто предполагаю) - структурные типы должны следовать правильному соглашению.
Например, Источник
содержит метод close
без скобок, что означает структурный тип def close (): модуль
не принимает Источник
.Аналогично, если я определю структурный метод как def close: Unit
, то объекты Java closeable
не будут приняты.
В дополнение к уже приведенным ответам я хотел бы подчеркнуть два момента:
Возможность определять методы без списка параметров - это способ реализовать Единый принцип доступа . Это позволяет скрыть разницу между полями и методами, что упрощает последующие изменения реализации.
Вы можете вызвать метод, определенный как def foo () = 5
, используя foo
, но вы не можете вызвать метод, определенный как def foo = 5
с использованием foo ()
Что это значит, когда я использую def для определения поля в Scala
Вы не можете определить поле, используя def
.
Похоже, что в обоих случаях я получаю переменную foo, на которую я могу ссылаться без скобок, всегда равной 5.
Нет, в обоих случаях вы получаете метод foo
, который можно вызывать без скобок.
Чтобы увидеть это, вы можете использовать javap
:
// Main.scala
object Main {
def foo1 = 5
def foo2() = 5
}
F:\MyProgramming\raw>scalac main.scala
F:\MyProgramming\raw>javap Main
Compiled from "main.scala"
public final class Main extends java.lang.Object{
public static final int foo2();
public static final int foo1();
}