Что делает ключевое слово "yield" в Ruby?
Я столкнулся со следующим кодом Ruby:
class MyClass
    attr_accessor :items
    ...
    def each
        @items.each{|item| yield item}
    end
    ...
end
Что делает метод each? В частности, я не понимаю, что делает yield.
8 ответов:
Это пример того, как вы создаете свой пример кода:
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и остановится, когда он достигнет последнего элемента, избегая ошибки и сохраняя вещи красивыми и чистыми.
Когда вы пишете метод, который принимает блок, вы можете использовать ключевое слово
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
Метод Ruby, который получает блок кода, вызывает его, вызывая его с ключевым словом
yield. Он может быть использован для итерации по списку, но это не итератор, как то, что вы найдете в других языках.Вот хорошее объяснение, которое объясняет это лучше, чем я когда-либо смог бы.
yieldговорит ruby, чтобы вызвать блок, переданный методу, давая ему свой аргумент.
yieldвыдаст ошибку, если метод не был вызван с блоком, где оператор asreturnне выдает ошибку.
returnможет отправлять только единичные значения, где asYieldвозвращает объект огромных значений.
В моем понимании 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
Меня зовут по имени 12
Выход будет называться с идентификатором 14
Меня зовут по имени 14
Как работает yield?
Поэтому, когда функция
nameвыполняется везде, где появляется выход, выполняется блочный код. Этоname {|i| puts "I am called by yield name #{i}"}Вы можете видеть, что есть слово
yield 12yield запускает код внутри блока передавая 12 как значениеi.Вот пример игры для него:
def load_game puts "Loading" yield end load_game { puts "Game loaded" }Это выведет
game loadedСразу после печатиloading:Загрузка
Игра Загружена
Чистый эффект-это вызов .каждый на экземпляре MyClass-это то же самое, что и вызов .каждый по своему .предметы этого экземпляра.
Как Новичок, просматривая ряд ответов, я запутался, пока не наткнулся на ответ Абхи.
Команда yield приостанавливает выполнение кода в методе и вместо этого передает управление обратно в блок кода, который вызвал его, выполняет этот код, а затем продолжает выполнение остальной части метода после этого. Вот пример, который прояснил это для меня:
def hello puts "hello" yield puts "world" end hello do puts "there" endВывод:
Привет
Там
Мир