Я столкнулся со следующим кодом Ruby:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
Что делает метод each
? В частности, я не понимаю, что делает yield
.
Я столкнулся со следующим кодом Ruby:
class MyClass
attr_accessor :items
...
def each
@items.each{|item| yield item}
end
...
end
Что делает метод each
? В частности, я не понимаю, что делает yield
.
Это пример, который выводит ваш пример кода:
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
приведет к ошибке, если метод не был вызван с блоком, где в качестве оператора return
не возникает ошибка.
return
может отправлять только одиночные значения, где yield
возвращает объект с огромными значениями.
Чистый эффект заключается в том, что вызов .each в экземпляре MyClass совпадает с вызовом .each на .items этого экземпляра.
Как новичок, просмотрев несколько ответов, я смутил меня, пока не ударил ответ Abhi.
команда yield приостанавливает выполнение кода в методе и вместо этого передает управление обратно в блок кода, который его вызывает, выполняет этот код и затем продолжает выполнение остальной части метода после этого. Вот пример, который прояснил это для меня:
def hello
puts "hello"
yield
puts "world"
end
hello do
puts "there"
end
Вывод:
Привет
есть
мир
Как cpm сказал, что он берет блок и выполняет его
def my_method
yield
end
my_method do
puts "Testing yield"
end
Testing yield
=> nil
В соответствии с моим пониманием 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}"}
Вывод:
Вызов будет вызываться с id из 12
Я вызывается именем yield 12
Вызов будет вызываться с идентификатором 14
Я вызываю имя урока 14
Как работает работа?
Итак, когда функция 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
:
Загрузка
Игра загружена