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

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

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

что значит each метод do? В частности, я не понимаю, что 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. The 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 приведет к ошибке, если метод не был вызван с блоком, где as return оператор не производит ошибку.

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


согласно моему пониманию 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

как работает выход?

когда 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 

выход:

привет

здесь

мир


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

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

def my_method
  yield
end


my_method do
  puts "Testing yield"
end

Testing yield
=> nil