Неявная область возвращаемого значения в Ruby

Я использую самоопределение include? метод для изучения разницы между явным и неявным возвратом. Я это понимаю #each возвращает коллекцию итеративно, поэтому я считаю, что мне нужно поместить мои истинные / ложные неявные возвращения в правильное место, но когда я это делаю, я возвращаю коллекцию, и я не уверен, что нужно изменить.

def self.include?(array, search_item)
  array.each do |elem|
    if elem == search_item
      true
    end
  end
end

Ниже приведены тесты, которые я проверяю, но я не понимаю, как правильно сопоставить результаты. Почему они не совпадают или как я должен понимать сферу неявного возврата?

  result = MethodReturns.include?(numbers_array, 4)
  expect(result).to eq(true)

  result = MethodReturns.include?(numbers_array, 7)
  expect(result).to eq(false)

3 ответа

Решение

Вы хотите изменить на:

def self.include?(array, search_item)
  array.each do |elem|
    if elem == search_item
      return true
    end
  end
  return false
end

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

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

def do_stuff()
  [1, 2, 3]. each do |num|
    true if num == num
  end
end

p do_stuff

--output:--
[1, 2, 3]

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

Вот пример метода, который неявно возвращает true:

def do_stuff()
  [1, 2, 3]. each do |num|
    #blah
  end

  true
end

Метод each() по-прежнему возвращает массив, но метод each() не является оператором LAST, который выполняется в методе do_stuff().

В вашем примере вы можете сделать это:

def do_stuff(target)
  found = false

  [1, 2, 3]. each do |num|
    found = true if num == target
  end

  found
end


p do_stuff(2)

--output:--
true

Однако это решение тратит впустую ресурсы, потому что метод each() продолжает итерацию по массиву после того, как найдено совпадение. Например, если в вашем массиве было 1 миллион элементов, и было найдено совпадение с индексом 0 в массиве, метод each() без необходимости продолжал бы итерацию по оставшимся 999 999 элементам. С другой стороны, явный возврат при обнаружении совпадения завершит цикл.

Явно писать никогда не ошибочно return val, По мере того, как вы становитесь более опытным, вы можете отбросить часть возврата - КОГДА ПОДХОДИТ - чтобы показать мир, в котором вы знаете рубин... однако время от времени опуская return все равно сбьет тебя с толку.

Если вы используете явный return внутри вашего each block - достижение этого кода приведет к немедленному возвращению значения (остановка итерации). Это из-за нелокальной возможности возврата блоков:

Блоки Ruby поддерживают non-local-return, что означает, что возврат из блока ведет себя идентично возврату из исходного контекста блока.

Так что ваш код должен работать правильно, если вы просто используете явный return:

def self.include?(array, search_item)
  array.each do |elem|
    if elem == search_item
      return true
    end
  end
end
Другие вопросы по тегам