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

Я хотел рассказать об одном из первых методов массива Ruby, с которым сталкивается большинство программистов, каждый. Каждый из них может быть вызван для массивов или хэшей. Когда каждый из них вызывается для наборов данных, он всегда возвращает исходный набор данных без каких-либо изменений. Это означает, что независимо от того, что происходит внутри итерации, даже если вы каким-то образом измените исходный набор данных, возвращаемое значение все равно будет отправленным исходным массивом.

array = [1,2,3,4,5]
array.each { |element| element + 1 } 
  #[1,2,3,4,5]
array 
  #[1,2,3,4,5]

В приведенном выше фрагменте, когда каждый вызывается в массиве, он проходит через каждый элемент массива и «что-то делает» с ним, в данном случае добавляет к нему 1. Обратите внимание, что исходный массив не изменяется, а выходным значением является значение, введенное в массив.

Так почему это полезно? Это помогает понять, как работают другие итераторы в ruby, и служит основой для таких методов, как map, all?, none?, reject, select, each_with_index и т. д.

Под капотом каждый пишется похоже на:

def each(dataset)
  index = 0
  while index < dataset.length
    yield(dataset[i])
    index += 1
  end
  dataset
end
-- or --
Class Array
  def each
    index = 0
    while index < self.length
      yeild(self[index]
      index += 1
    end
    self
  end
end

Из рубиновых документов:

VALUE
rb_ary_each(VALUE ary)
{
    long i;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_AREF(ary, i));
    }
    return ary;
}

В конце метода переданный набор данных (или себя, если вы следуете второму примеру) будет возвращен обратно пользователю. Это помогает объяснить, почему, если пользователь манипулирует массивом, используя каждое из них, возвращается исходное значение, но исходный набор данных перезаписывается.

array = [1,2,3,4,5]
p array.each { |element| array = "some modification"} 
  #[1,2,3,4,5], note that array does not equal [1,2,3,4,5] but return statment will be.

p array 
  #"some modification"

Хотя это крайне непрактично, это можно сделать. В конце концов, массив — это просто переменная. Он начинается с указания на [1,2,3,4,5] в памяти. В итераторе мы сбрасываем переменную массива на «некоторую модификацию», и обратите внимание, что мы делаем это несколько раз. В конце итерации исходный массив по-прежнему возвращается, потому что именно для этого был запрограммирован каждый метод.

Я надеюсь немного глубже погрузиться в другие методы на разных языках и выяснить небольшие нюансы, которые заставляют их тикать или вычислять. В большинстве случаев это может быть рубин, так как он занимает особое место в моем сердце.