Должен ли я использовать возвраты в многострочных методах Scala? - PullRequest
4 голосов
/ 20 декабря 2010

Возможно, это просто мой опыт в более императивном программировании, но мне нравится, когда в моем коде есть операторы return.

Я понимаю, что в Scala возвраты не нужны во многих методах, потому что независимо от того, какое последнее вычисленное значение возвращается, по умолчанию. Я понимаю, что это имеет смысл для "одной строки", например,

def square(x) = x * x

Я также понимаю категорический случай использования явных возвратов (когда у вас есть несколько ветвей, которые может взять ваш код, и вы хотите выйти из метода для разных ветвей, например, если произойдет ошибка). Но как насчет многострочных функций? Разве это не было бы более читабельным и имело бы больше смысла, если бы был явный возврат, например,

def average(x: List[Int]) : Float = {
  var sum = 0
  x.foreach(sum += _)
  return sum / x.length.toFloat
}

Ответы [ 5 ]

11 голосов
/ 20 декабря 2010
def average(x: List[Int]) : Float = 
  x.foldLeft(0)(_ + _) / x.length.toFloat

ОБНОВЛЕНИЕ: Хотя я стремился показать, как итеративный код можно превратить в функциональное выражение, @soc справедливо заметил, что еще более короткая версия - x.sum / x.length.toFloat

, я обычно нахожу, что вСкала мне меньше нужна, чтобы «вернуться в середину».Кроме того, большая функция разбита на более мелкие выражения, более понятные для разума.Поэтому вместо

var x = ...
if (some condition) x = ...
else x = ...

я бы написал, если (какое-то условие) ... еще ....

Подобные вещи происходят с использованием выражений соответствия.И у вас всегда могут быть вспомогательные вложенные классы.

Как только вы освоитесь со многими формами выражений, которые оценивают результат (например, 'if') без оператора return, тогда наличие одного в ваших методах выглядит не по назначению.place.

На одном из рабочих мест у нас было правило не иметь «return» в середине метода, поскольку читателю вашего кода легко его пропустить.Если «return» находится только в последней строке, какой смысл вообще его иметь?

10 голосов
/ 20 декабря 2010

return не говорит вам ничего лишнего, поэтому я считаю, что это на самом деле мешает моему пониманию того, что происходит. Из курса возвращается; других заявлений нет!

И это также хорошая идея, чтобы избавиться от привычки использовать return, потому что действительно неясно, куда вы возвращаете в , когда вы используете сильно функциональный код:

def manyFutures = xs.map(x => Futures.future { if (x<5) return Nil else x :: Nil })

Куда должен возвращаться исполнитель? Снаружи manyFutures? Просто внутренний блок?

Так что, хотя вы можете использовать явные возвраты (по крайней мере, если вы явно аннотируете тип возвращаемого значения), я предлагаю вам вместо этого попытаться привыкнуть к обычаю «последний оператор является возвращаемым значением».

3 голосов
/ 21 декабря 2010

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

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

def average(xs: List[Int]): Float = {
   var sum = 0
   xs.foreach(sum += _)
   sum / xs.length.toFloat
}

Это описание довольно близко к английской версии, игнорируя первые две строки функции. Мы можем выделить функцию sum, чтобы получить более декларативное описание:

def average(xs: List[Int]): Float = {
   def sum(xs: List[Int]): Int = // ...
   sum(xs) / xs.length.toFloat
}

В декларативном определении оператор return читается довольно неестественно, поскольку он явно делает акцент на выполнении чего-либо.

2 голосов
/ 20 декабря 2010

Я не пропускаю оператор return в конце метода, потому что он не нужен. Кроме того, в Scala каждый метод возвращает значение - даже методы, которые не должны возвращать что-либо. Вместо void возвращается тип Unit:

def x { println("hello") }

можно записать как:

def x { println("hello"); return Unit }

Но println уже возвращает тип Unit - таким образом, когда вы явно хотите использовать оператор return, вы должны использовать его в методах, которые также возвращают Unit. В противном случае у вас не будет постоянного идентичного кода сборки.

Но в Scala есть возможность разбить ваш код множеством маленьких методов:

def x(...): ReturnType = {
  def func1 = ... // use funcX
  def func2 = ... // use funcX
  def func3 = ... // use funcX
  funcX
}

Явно используемый оператор возврата не помогает лучше понять код.

Также Scala имеет мощную базовую библиотеку, которая позволяет решать многие проблемы с меньшим количеством кода:

def average(x: List[Int]): Float = x.sum.toFloat / x.length
0 голосов
/ 20 декабря 2010

Я считаю, что вы не должны использовать return, я думаю, что это как-то противоречит элегантной концепции, что в Scala все является выражением, которое что-то оценивает.

Как и ваш average метод: это просто выражение, которое оценивается как Float, нет необходимости возвращать что-либо, чтобы это работало.

...