Это хороший стиль, чтобы явно вернуться в Ruby? - PullRequest
146 голосов
/ 21 июня 2009

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

Является ли "Ruby Way" для явного ввода return в методы? Я видел, как это было сделано с и без, но есть ли правильный способ сделать это? Есть ли право время сделать это? Например:

def some_func(arg1, arg2, etc)
  # Do some stuff...
  return value # <-- Is the 'return' needed here?
end

Ответы [ 8 ]

214 голосов
/ 30 ноября 2012

Старый (и "отвеченный") вопрос, но я добавлю два цента в качестве ответа.

TL; DR - Вы не обязаны это делать, но в некоторых случаях это может сделать ваш код более понятным.

Хотя не использование явного возврата может быть «способом Ruby», это сбивает с толку программистов, работающих с незнакомым кодом, или незнакомых с этой функцией Ruby.

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

def plus_one_to_y(x)
    @y = x + 1
end

Это должна была быть функция, которая возвращала значение, или нет? Действительно сложно сказать, что имел в виду разработчик, поскольку он одновременно назначает переменную экземпляра и возвращает возвращаемое значение.

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

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
end

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

Реальный вопрос сейчас заключается в следующем: ожидало ли что-нибудь возвращаемое значение? Это что-то сломало или нет? Это что-то сломает в будущем? Кто знает! Только полный просмотр кода всех звонков даст вам знать.

Так что, по крайней мере, для меня наилучший практический подход - либо четко заявить, что вы что-то возвращаете, если это имеет значение, либо вообще ничего не возвращать, если это не так.

Так что в случае нашей маленькой демонстрационной функции, если мы хотим, чтобы она возвращала значение, она была бы написана следующим образом ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    return @y
end

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

С другой стороны, можно написать это так и пропустить оператор return ...

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    @y
end

Но зачем вообще опускать слово return? Почему бы просто не положить это туда и не дать на 100% понять, что происходит? Это буквально не повлияет на способность вашего кода выполнять.

66 голосов
/ 21 июня 2009

Нет. Хороший стиль Ruby обычно использует явные возвраты только для досрочного возврата . Ruby хорош в коде минимализм / неявная магия.

Тем не менее, если явное возвращение сделает вещи более понятными или более легкими для чтения, это ничего не повредит.

31 голосов
/ 21 июня 2009

Я лично использую ключевое слово return, чтобы различать то, что я называю функциональными методами , т.е. методами, которые выполняются в основном для возвращаемого значения, и процедурными методами , которые выполняются в основном за их побочные эффекты. Таким образом, методы, в которых важно возвращаемое значение, получают дополнительное ключевое слово return, чтобы привлечь внимание к возвращаемому значению.

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

И последнее, но не менее важное: я также использую это различие с блоками: функциональные блоки получают фигурные скобки, процедурные блоки (то есть блоки, которые «делают» что-то) получают do / end.

Однако я стараюсь не быть религиозным по этому поводу: с блоками, фигурными скобками и do / end имеют другой приоритет, и вместо того, чтобы добавлять явные скобки для устранения неоднозначности выражения, я просто переключаюсь на другой стиль. То же самое относится и к вызову метода: если добавление скобок вокруг списка параметров делает код более читабельным, я делаю это, даже если рассматриваемый метод носит процедурный характер.

13 голосов
/ 30 июля 2013

На самом деле важно различать:

  1. Функции - методы, выполняемые для их возвращаемого значения
  2. Процедуры - методы, выполняемые для их побочных эффектов

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

Чтобы решить эту проблему, возьмите лист из книги Скалы и Хаскелла и попросите ваши процедуры явно вернуть nil (он же Unit или () на других языках).

Если вы следуете этому, то использование явного синтаксиса return или не только становится вопросом личного стиля.

Для дальнейшего различения функций и процедур:

  1. Скопируйте замечательную идею Йорга В. Миттага о написании функциональных блоков с фигурными скобками и процедурных блоков с do/end
  2. Когда вы вызываете процедуры, используйте (), тогда как при вызове функций не

Обратите внимание, что Jörg W Mittag на самом деле выступал с другой стороны - избегая () s для процедур - но это не рекомендуется, потому что вы хотите, чтобы вызовы метода побочных эффектов были четко различимы от переменных, особенно когда arity равен 0. 1033 * Руководство по стилю Scala при вызове метода для получения подробной информации.

7 голосов
/ 24 января 2016

Руководство по стилю гласит, что вы не должны использовать return в своем последнем утверждении. Вы все еще можете использовать его , если он не последний . Это одно из соглашений, которым строго следует сообщество, и вы должны, если вы планируете сотрудничать с кем-либо, использующим Ruby.


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

  • Во-первых, это не совсем исключительно для Ruby. Например, в Perl тоже есть неявные возвраты.
  • Во-вторых, большинство людей, к которым это относится, - выходцы из алгольских языков. Большинство из них на «более низкий уровень» , чем Ruby, поэтому вам нужно написать больше кода, чтобы что-то сделать.

Обычная эвристика для длины метода (исключая методы получения / установки) в Java - это один экран . В этом случае вы, возможно, не видите определение метода и / или уже забыли о том, откуда вы возвращались.

С другой стороны, в Ruby лучше придерживаться методов длиной менее 10 строк . Учитывая это, можно задаться вопросом, почему он должен писать на ~ 10% больше заявлений, когда они явно подразумеваются.


Поскольку в Ruby нет методов void , и все намного проще, вы просто добавляете накладные расходы ни для одного из преимуществ, если вы используете явные return s.

4 голосов
/ 30 января 2015

Я согласен с Беном Хьюзом и не согласен с Тимом Холтом, потому что в вопросе упоминается окончательный способ, которым Python делает это, и спрашивает, есть ли у Ruby аналогичный стандарт.

Да.

Это настолько известная особенность языка, что любой, кто ожидал отладить проблему в ruby, должен был знать о ней.

1 голос
/ 21 июня 2009

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

0 голосов
/ 21 июня 2009

Как сказал Бен. Тот факт, что «возвращаемое значение метода ruby ​​является возвращаемым значением последнего оператора в теле функции», приводит к тому, что ключевое слово return редко используется в большинстве методов ruby.

def some_func_which_returns_a_list( x, y, z)
  return nil if failed_some_early_check


  # function code 

  @list     # returns the list
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...