Как получить размер клонированного ленивого перечислителя

У нас есть объект Enumerator::Lazy

a = [1,2,3].lazy.map {} #=> <Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>
a.size #=> 3
a.clone.size #=> nil

У кого-нибудь есть правильное объяснение такого поведения? я знаю это size возвращает размер перечислителя или ноль, если он не может быть вычислен лениво. Когда мы клонируем объект, он возвращается

a.clone #=> <Enumerator::Lazy:<Enumerator::Generator:0x00007fdaa80218d8>:each>

1 ответ

Решение

Я знаю, что размер возвращает размер перечислителя или ноль, если его нельзя вычислить лениво.

size для Enumerator не обязательно реальная вещь (или, по крайней мере, не то, что можно было бы подумать), что может быть причиной того, что это изменение было осуществлено.

Например

[1,2,3].to_enum.size
#=> nil

[1,2,3].to_enum(:each) { 1 }.size #=> 1
#=> 1

или еще лучше

[1,2,3].to_enum(:each) { "A" }.size 
#=> "A" 

Когда мы клонируем объект, он возвращается a.clone #=> <Enumerator::Lazy<Enumerator::Generator:0x00007fdaa80218d8>:each>

Похоже, что это изменение в 2.4, когда кажется, что он возвращается к: каждый метод (возможно, через enum_for) потому что в 2.3 ссылка на map сохраняется как размер. Очевидно, что из-за реверсии не произошло итерации, и размер не может быть определен "ленивым" образом и, таким образом, nil

Другие вопросы по тегам