Что делает ключевое слово "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 12
yield запускает код внутри блока передавая 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
Вывод:
Привет
Там
Мир