Подтвердить что ты не робот

Что делает ключевое слово "yield" в Ruby?

Я столкнулся со следующим кодом Ruby:

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

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

4b9b3361

Ответ 1

Это пример, который выводит ваш пример кода:

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 и останавливаться, когда оно достигнет последнего элемента, избегая ошибки и сохраняя все хорошее и чистое.

Ответ 2

Когда вы пишете метод, который принимает блок, вы можете использовать ключевое слово 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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

Как новичок, просмотрев несколько ответов, я смутил меня, пока не ударил ответ Abhi.

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

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

hello do
    puts "there"
end 

Вывод:

Привет

есть

мир

Ответ 7

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

def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil 

Ответ 8

В соответствии с моим пониманием 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:

Загрузка

Игра загружена