2015-11-19 5 views
1

я ожидал row быть [0, 0, 0, 0] и row_index быть nil в следующем:`each` цикл с дополнительным параметром

img_array = [ 
    [0, 0, 0, 0], 
    [0, 0, 0, 0], 
    [0, 0, 0, 0], 
    [0, 1, 0, 0], 
    [0, 0, 0, 0], 
    [0, 0, 0, 0] 
] 

img_array.each do |row, row_index| 
    ... 
end 

На самом деле, это row0 и row_index является 0. Может кто-нибудь объяснить это?

+0

Невозможно воспроизвести. Это даже не актуально. – sawa

+0

@sawa Он отлично работает для меня в ruby-2.2.2 и дает описанный результат. –

ответ

3
img_array = [ 
    [0, 1, 2, 3], 
    [4, 5, 6, 7], 
    [8, 9, 0, 1] 
] 

Мы имеем:

enum = img_array.each 
    #=> #<Enumerator: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]]:each> 

Array#each поэтому создает перечислитель, который является экземпляром класса Enumerator. Метод Enumerator#each проходит каждый элемент enum к блоку и присваивает блок переменные:

enum.each { |row, row_index| puts "row=#{row}, row_index=#{row_index}" } 
    # row=0, row_index=1 
    # row=4, row_index=5 
    # row=8, row_index=9 

Мы можем увидеть, что каждый из элементов enum являются с помощью метода Enumerator#next:

enum.next #=> StopIteration: iteration reached an end 

Упс! Я забыл сбросить перечислитель:

enum.rewind 
    #=> #<Enumerator: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]]:each> 

enum.next #=> [0, 1, 2, 3] 
enum.next #=> [4, 5, 6, 7] 
enum.next #=> [8, 9, 0, 1] 
enum.next #=> StopIteration: iteration reached an end 

В качестве альтернативы, мы могли бы преобразовать перечислитель в массив (нет необходимости rewind):

enum.to_a #=> [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 0, 1]] 

Когда элемент ([0, 1, 2, 3]) передается к блоку, блочные переменные присваиваются следующим образом:

row, row_index = [0, 1, 2, 3]   #=> [0, 1, 2, 3] 
row          #=> 0 
row_index        #=> 1 

Если переменные были |row, row_index, col_index|, назначение будет:

row, row_index, col_index = [0, 1, 2, 3] #=> [0, 1, 2, 3] 
row          #=> 0 
row_index        #=> 1 
col_index        #=> 2 

Если бы они были |row, row_index, *rest|, это было бы:

row, row_index, *rest = [0, 1, 2, 3]  #=> [0, 1, 2, 3] 
row          #=> 0 
row_index        #=> 1 
rest          #=> [2, 3] 

Это называется parallel (or multiple) assignment. Вы можете прочитать правила для таких назначений по ссылке, которую я дал.

+1

Отличный ответ. Формируйте это, я понял, что на самом деле был вопрос OP: D –

+0

Cary это имеет смысл! Благодарим вас за ваш четкий, углубленный ввод. Я лучше понимаю, как работают счетчики. – EricOrel

1

Метод .each() в массиве в Ruby вызовет ваш блок только с одним аргументом. Так что, если вы пишете код, как это:

img_array.each do |row, row_index| 
    # do something here 
end 

Это эквивалентно следующему:

img_array.each do |element| 
    row, row_index = element 
    # and now 
    # row = element[0] 
    # row_index = element[1] 
end 

Я привел пример, что легче понять

img_array = [ 
    ['a', 'b', 'd', 'e'], 
    ['f', 'g', 'h', 'j'] 
] 

img_array.each do |row, row_index| 
    p row 
    p row_index 
end 

а также результатом будет:

"a" 
"b" 
"f" 
"g" 

Выполнить его в Интернете здесь: https://ideone.com/ifDaVZ

+1

Я проверил его, и он работает так же, как вы сказали. Благодарим вас за разъяснения. Это действительно помогло мне! – EricOrel

+0

@ EricOrel Добро пожаловать. Если этот ответ решает вашу проблему, отметьте этот ответ как принятый, чтобы другие могли найти его проще. –

Смежные вопросы