Объявление метода Scala "def": двоеточие и равно

Я нахожусь на ранних стадиях изучения Scala, и я заметил разные способы объявления методов.

Я установил, что отсутствие знака равенства делает метод пустым (возвращая Unit вместо значения), и использование знака равенства возвращает фактическое значение, так

def product(x: Int, y: Int) {
  x*y
}

вернусь () (Единица измерения), но

def product(x: Int, y: Int) = {
  x*y
}

вернет произведение двух аргументов (x*y)

Я заметил третий способ объявления методов - с двоеточием. Вот пример

def isEqual(x: Any): Boolean

Чем это отличается от = нотация? И в каких ситуациях лучше будет использовать этот способ?

6 ответов

Решение

Когда вы используете двоеточие (и используете равно), вы явно определяете тип возвращаемого значения метода.

// method return Boolean value
def m(a : Int) : Boolean = a > 0 

Когда вы не используете двоеточие и используете равные, вы разрешаете компилятору scala выводить сам тип возвращаемого значения.

// method has return type of last expression (Boolean)
def m(a : Int) = a > 0 

Когда вы не используете ни двоеточие, ни равно, ваш метод имеет возвращаемый тип класса Unit.

// method has Unit return type
def m(a : Int){ 
    a > 0 
}

Если вы не хотите возвращаемый тип, то вы использовали

scala> def product(x: Int, y: Int) { //in lack of = it explicit uses Unit 
     |   x*y
     | }
product: (x: Int, y: Int)Unit
//equivalent to below
scala> def product(x: Int, y: Int):Unit={ 
     |   x*y
     | }
product: (x: Int, y: Int)Unit

и когда ты пишешь

scala> def product(x: Int, y: Int) = {  //here it explicit detect return type
     |   x*y
     | }
product: (x: Int, y: Int)Int
//equivalent to below
scala> def product(x: Int, y: Int):Int = {
     |   return x*y
     | }
product: (x: Int, y: Int)Int

Другие прекрасно объяснили различия между различными декларациями:

def foo: Boolean = true // explicitly declare the return type

а также

def foo = true // let the compiler to implicitly infer Boolean

При этом я должен предупредить вас против

def foo { }

Это называется процедурный синтаксис, и вы никогда не должны его использовать, так как он уже устарел (с 29 октября 2013 г.), хотя вы получите предупреждение об устаревании только под -Xfuture флаг.

Всякий раз, когда вы должны объявить метод, возвращающий Unit (которого следует избегать, насколько это возможно, поскольку это означает, что вы полагаетесь на побочные эффекты), используйте следующий синтаксис

def foo: Unit = { }

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

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

trait {
  def foo
}

законно, но тип foo автоматически определяется как Unit, который почти никогда не того, что вы хотите.

Вместо этого делай

trait {
  def foo: Boolean
}

В Scala функция определяется как

def product(x: Int, y: Int): Int = {
  x*y
}

но там есть несколько "горячих клавиш", которые можно использовать

  1. Поскольку scala имеет хороший тип Inference, вы можете опустить тип (если только функция не является рекурсивной):

    def product(x: Int, y: Int) = { x*y }

  2. Все это выражение. поэтому функция должна возвращать значение. Последняя строка блока кода является возвращаемым значением. поэтому, если вы используете изогнутые скобки {}, последняя строка будет возвращена. если функция имеет только одну строку, то нет необходимости в изогнутых скобках.

    def product(x: Int, y: Int) = x*y

  3. Поскольку все должно возвращать значение "Нет значения" на самом деле Unit, Так что, если вы не хотите возвращать значимое значение (что означает, что вы делаете некоторые побочные эффекты), тогда используйте Unit в качестве возвращаемого значения:

    def product(x: Int, y: Int): Unit = x*y

  4. Использование функций без знака равенства - это просто еще один способ вернуть Unit (это также называется "синтаксис процедуры"):

    def product(x: Int, y: Int) { x*y }

def foo(arg) { sideEffects() } эквивалентно def foo(arg) = { sideEffects(); Unit }, Это плохой стиль, потому что он скрывает ваши намерения. (Легко пропустить =). Я рекомендую вам не использовать его.

def foo(arg) = { expression } это метод, который неявно разрешает тип выражения и имеет хороший стиль.

def foo(arg): Type является абстрактным определением метода с явным типом. Это не эквивалентно двум другим примерам, так как реализация не предусмотрена.

1) procedure syntax устарела из scala-2.11, избегайте этого.

def product(x: Int, y: Int) {
    x*y
}
// It always returns Unit. 
// creates confusion for most beginners. deprecated for good.

2) type inference синтаксис, в основном используется с маленькими / частными методами.

def product(x: Int, y: Int) = {
    x*y
}

Это помощь от компилятора, но иногда вывод компилятора может отличаться от того, что вы думаете.

3) type annotation синтаксис.

def product(x: Int, y: Int): Int = {
    x*y
}

Для открытых API рекомендуется явно указывать тип возвращаемого значения.

В некоторых случаях обязательно указывать тип возврата. Например:

  • при определении рекурсивных методов.

  • когда вывод компилятора более конкретен, но вам нужен универсальный тип возвращаемого значения (вместо HashMap Map).

  • Переопределить вывод компилятора. def getId(): Long = 1

  • Если return используется где угодно в теле метода.

Другие вопросы по тегам