Что делает ключевое слово yield в Ruby? - PullRequest
32 голосов
/ 01 декабря 2010

Я обнаружил следующий код Ruby:

class MyClass
    attr_accessor :items
    ...
    def each
        @items.each{|item| yield item}
    end
    ...
end

Что делает метод each? В частности, я не понимаю, что делает yield.

Ответы [ 8 ]

31 голосов
/ 01 декабря 2010

Это пример уточнения вашего примера кода:

class MyClass
  attr_accessor :items

  def initialize(ary=[])
    @items = ary
  end

  def each
    @items.each do |item| 
      yield item
    end
  end
end

my_class = MyClass.new(%w[a b c d])
my_class.each do |y|
  puts y
end
# >> a
# >> b
# >> c
# >> d

each зацикливается на коллекции.В этом случае он зацикливается на каждом элементе в массиве @items, инициализированном / созданном, когда я выполнял оператор new(%w[a b c d]).

yield item в методе MyClass.each передает item в прикрепленный блокдо my_class.each.Получаемый item назначается локальному y.

Помогает ли это?

Теперь рассмотрим подробнее, как работает each.Используя то же определение класса, вот некоторый код:

my_class = MyClass.new(%w[a b c d])

# This points to the `each` Enumerator/method of the @items array in your instance via
#  the accessor you defined, not the method "each" you've defined.
my_class_iterator = my_class.items.each # => #<Enumerator: ["a", "b", "c", "d"]:each>

# get the next item on the array
my_class_iterator.next # => "a"

# get the next item on the array
my_class_iterator.next # => "b"

# get the next item on the array
my_class_iterator.next # => "c"

# get the next item on the array
my_class_iterator.next # => "d"

# get the next item on the array
my_class_iterator.next # => 
# ~> -:21:in `next': iteration reached an end (StopIteration)
# ~>    from -:21:in `<main>'

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

Использование each с блоком будет перебирать приемник @items и останавливаться при достижении последнего элемента, избегая ошибки и сохраняя все в порядке и чистоте.

15 голосов
/ 01 декабря 2010

Когда вы пишете метод, который принимает блок, вы можете использовать ключевое слово yield для выполнения блока.

Например, each мог бы быть реализован в классе Array следующим образом:

class Array
  def each
    i = 0
    while i < self.size
      yield( self[i] )
      i = i + 1
    end
  end
end

MyClass#each занимает блок.Он выполняет этот блок один раз для каждого элемента в массиве items экземпляра, передавая текущий элемент в качестве аргумента.

Он может использоваться следующим образом:

instance = MyClass.new
instance.items = [1, 2, 3, 4, 5]
instance.each do |item|
  puts item
end
10 голосов
/ 01 декабря 2010

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

Здесь - хорошее объяснение, которое объясняет это лучше, чем я когда-либо смог бы.

5 голосов
/ 03 февраля 2017

Согласно моему пониманию yield выполняет код из блока.

def name
    puts "A yield will be called with id of 12"
    yield 12
    puts "A yield will be called with id of 14"
    yield 14
end


name {|i| puts "I am called by yield name #{i}"}

Вывод:

Вызов будет вызываться с идентификатором 12

Меня вызывает по yieldимя 12

Доход будет вызываться с идентификатором 14

Меня называют по имени выхода 14

Как работает доход?

Таким образом, когда функция name запускается везде, где возвращается yield, выполняется код блока.Это name {|i| puts "I am called by yield name #{i}"}

Вы можете видеть, что есть слово yield 12 yield запускает код внутри блока, передавая 12 как значение i.

Вот пример игры для него:

def load_game
    puts "Loading"

    yield

end


load_game { puts "Game loaded" }

Будет напечатано game loaded сразу после печати loading:

Загрузка

Game Loaded

5 голосов
/ 01 сентября 2015

yield говорит ruby ​​вызвать блок, переданный методу, передав ему аргумент.

yield выдаст ошибку, если метод не был вызван с блоком, где оператор return не выдает ошибку.

return может отправлять только отдельные значения, гдеas Yield возвращает объект огромных значений.

4 голосов
/ 11 сентября 2016

Как новичок, просмотр ряда ответов смущал меня, пока я не нажал на ответ Абхи.

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

def hello
    puts "hello"
    yield 
    puts "world"
end

hello do
    puts "there"
end 

Вывод:

привет

там

мир

4 голосов
/ 01 декабря 2010

Чистый эффект заключается в том, что вызов .each для экземпляра MyClass аналогичен вызову .each для .items этого экземпляра.

3 голосов
/ 20 августа 2014

Как сказал cpm, он берет блок и выполняет его

Простой пример:

def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...