какова точка возврата в Ruby?

79

В чем разница между returnи простым помещением переменной, например следующей:

без возврата

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  mood
end

возвращение

def write_code(number_of_errors)
  if number_of_errors > 1
    mood =  "Ask me later"
  else
    mood = puts "No Problem"
  end  
  return mood
end
Thenengah
источник

Ответы:

118

return позволяет рано вырваться:

def write_code(number_of_errors)
  return "No problem" if number_of_errors == 0
  badness = compute_badness(number_of_errors)
  "WHAT?!  Badness = #{badness}."
end

Если number_of_errors == 0, то "No problem"будет возвращено сразу. Однако, как вы заметили, в конце метода в этом нет необходимости.


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

def last_name(name)
  return nil unless name
  name.split(/\s+/)[-1]
end

Если вы вызовете эту функцию как last_name("Antal S-Z"), она вернется "S-Z". Если вы назовете его как last_name(nil), он вернется nil. Если return не прервать немедленно, он попытается выполнить nil.split(/\s+/)[-1], что вызовет ошибку.

Антал Спектор-Забуски
источник
хорошо, хороший пример. поэтому return сохраняет возвращаемое значение, но позволяет выполнению остальной части метода. Не могу дождаться, чтобы использовать это.
thenengah 05
4
Нет, наоборот: return сразу выходит из метода. Если вы подумаете об этом примере, было бы бесполезно вычислять плохое, если вы знаете, что все в порядке. Я отредактирую свой ответ, чтобы было понятнее.
Antal Spector-Zabusky
8
Вы можете использовать returnи breakт. Д. Без параметров - они вернутся nilпо умолчанию.
Nakilon 05
38

Использование «return» не нужно, если это последняя строка, выполняемая в методе, поскольку Ruby автоматически возвращает последнее вычисленное выражение.

Вам даже не нужно это окончательное «настроение», и вам не нужны эти назначения в операторе IF.

def write_code(number_of_errors)
    if number_of_errors > 1
       "ERROR"
    else
       "No Problem"
    end  
end

puts write_code(10)

Вывод:

ОШИБКА

Даннеу
источник
37
Исходя из фона, отличного от Ruby, этот вывод определенно WTF. :)
Патрик
return может выйти из выполнения раньше. Это работа для.
Joe.wang 06
1
Return также может быть полезен, если метод возвращает nil вместо того, что было последним вычисленным выражением, поэтому иногда вы увидите возврат без аргументов в конце методов.
garythegoat
1
@garythegoat: или вы можете просто написать nil.
Karoly Horvath
4

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

list.select{|k| k.meets_criteria}.length == 0

в некоторых ситуациях, но

list.each{|k| return false if k.meets_criteria}

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

РЕДАКТИРОВАТЬ:

Чтобы добавить гибкости, рассмотрите следующую строку кода:

list_of_method_names_as_symbols.each{|k| list_of_objects.each{|j| return k if j.send(k)}}

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

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

РЕДАКТИРОВАТЬ

Следует отметить, что я предполагаю, что эта строка находится внутри метода, а не блока.


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

Philosodad
источник
breakв этих случаях даже более полезен.
Nakilon 05
4

Руби всегда возвращается! лучший способ

def write_code(number_of_errors)
  (number_of_errors > 1)? "ERROR" : "No Problem"
end

это означает, что если number_of_errors> 1, он вернет ERROR, иначе нет проблем

msroot
источник
3

Его красивый рубин дает эту хорошую возможность не указывать явно оператор возврата, но я просто чувствую, что в качестве стандарта программирования всегда следует стремиться указывать операторы возврата везде, где это необходимо. Это помогает сделать код более читабельным для тех, кто имеет разный опыт, например, C ++, Java, PHP и т. Д., И изучает Ruby. Оператор return ничему не повредит, так зачем же пропускать обычный и более стандартный способ возврата из функций.

Куш
источник
4
«Так зачем пропускать обычный и более стандартный способ возврата из функций» ← потому что в Ruby пропуск return является обычным стандартом. Если вы видите returnхорошо оформленный код Ruby, это должно быть по какой-то причине, например , преждевременный выход из строя . Попытки применить соглашения о стилях кода с одного языка на другой только затрудняют работу опытных программистов и сохранение единообразия собственного стиля кода.
Дэвид Моулс
Я все еще ловлю себя на том, что ставлю точки с запятой в конце строк
gdbj
Разве это не №2 в дзен Руби: «неявное лучше, чем явное»? ;-)
Mark
1

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

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
end

и скажем, вы добавили оператор отладки (или ведения журнала):

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
end

Теперь угадайте, что. Вы нарушили свой код, потому что putsвозвращает nil, который теперь становится значением, возвращаемым функцией.

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

def write_code(number_of_errors)
  if number_of_errors > 1
     mood = "Ask me later"
  else
     mood = "No Problem"
  end  
  puts "### mood = #{mood}"
  mood
end
Том Хундт
источник
-1

Отсутствие необходимости returnв последней строке функции - всего лишь синтаксический сахар Ruby. В большинстве процедурных языков вам нужно писать returnв каждой (непустой в C ++) функции.

Накилон
источник
3
Я бы не назвал это синтаксическим сахаром ... основная особенность здесь в том, что почти все является выражением . ifоператоры, блоки операторов. Вот что позволяет эту выразительность.
Karoly Horvath
Я согласен с Кароли - это не синтаксический сахар, потому что все является выражением.
fatuhoku