реализация каждой функции с использованием 'для каждого' в ruby - PullRequest
3 голосов
/ 14 декабря 2011

Я изучал ruby ​​и хотел знать, как «каждый» реализован в классе массива. Я видел одну документацию здесь , и похоже, что так написано «каждый»;

# within class Array...
def each
  for each element
    yield(element)
  end
end

Я точно написал код выше (без комментария #) в консоли ruby ​​(я использую 1.9.2) и получил эту синтаксическую ошибку

:SyntaxError: (irb):2: syntax error, unexpected tIDENTIFIER, expecting keyword_do or '{' or '('
(irb):5: syntax error, unexpected keyword_end, expecting $end

Это происходит из-за неполной реализации класса массива (т. Е. «Элемент» не определен или это из-за чего-то еще? Я также хотел бы знать, как реализованы «каждая» и другие основные функции. Любая ссылка на Правильная документация / ответы были бы полезны. Дайте мне знать, если это дубликат (я не видел подобных вопросов). спасибо

Ответы [ 4 ]

12 голосов
/ 14 декабря 2011

Вы можете сделать это (не пропустите in):

class Array
  def each
    for element in self
      yield element
    end
  end
end

Но факт таков:

for element in array - это синтаксический сахар array.each

Таким образом, приведенный выше код преобразуется в это:

class Array
  def each
    each do |element|
      yield element
    end
  end
end

И вы переполняете стек.

7 голосов
/ 14 декабря 2011

Во-первых, синтаксис вашего оператора for отключен, он должен выглядеть примерно так: for element in elements, что почти эквивалентно elements.each { |element| ... }, за исключением того, что он не вводит новую область видимости. Фактически for реализован с использованием each, что можно увидеть, когда вы пытаетесь вызвать его для метода, у которого нет определенного each метода:

>> for element in nil
..   end
NoMethodError: undefined method `each' for nil:NilClass
    from (irb):1

Относительно вашей синтаксической ошибки: поскольку вы повторно открываете класс, когда анализатор Ruby видит автономный each, он использует self в качестве получателя, поэтому он переводит ваш оператор в for self.each element, где element - это tIDENTIFIER упомянуто, тогда как ожидалось что-то вроде self.each do |element| ... end.

Что касается реализации Array#each, она реализована на C и выглядит следующим образом

VALUE
rb_ary_each(VALUE array)
{
    long i;
    volatile VALUE ary = array;

    RETURN_ENUMERATOR(ary, 0, 0);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_PTR(ary)[i]);
    }
    return ary;
}

Это в основном то, что вы пытались написать на Ruby в C.

0 голосов
/ 14 января 2013

Это возможно при циклическом изменении диапазона от 0 до размера массива (исключено)

class Array
  def each
    for i in 0...self.size
      yield self[i]
    end
  end
end

Пример:

[1,2,3].each {|i| puts i}
1
2
3

Работает!

0 голосов
/ 14 декабря 2011

Array#each построен методом Ruby.Это не исправлено ни в одном драгоценном камне.Смотрите документацию здесь

...