Upgrade to Pro — share decks privately, control downloads, hide ads and more …

從 Enumerator 看 Ruby 的迭代器

從 Enumerator 看 Ruby 的迭代器

RubyConf TW 2019

蒼時弦や

July 27, 2019
Tweet

More Decks by 蒼時弦や

Other Decks in Programming

Transcript

  1. Review Ruby s Iterator
    with Enumerator
    Photo by Tine Ivanič on Unsplash

    View Slide

  2. WEB DEVELOPER
    GAME DEVELOPER


    ݭ໵
    @elct9620

    View Slide

  3. View Slide

  4. As a Ruby developer,
    We use #each every day

    View Slide

  5. BUT
    How it works?

    View Slide

  6. #iterator
    Photo by Joel Fulgencio on Unsplash

    View Slide

  7. def iterator(&block)
    yield 1
    yield 2
    yield 3
    end

    View Slide

  8. VALUE
    rb_block_call(VALUE obj, ID mid, int argc, const VALUE * argv,
    VALUE (*bl_proc) (ANYARGS), VALUE data2)
    {
    struct iter_method_arg arg;
    arg.obj = obj;
    arg.mid = mid;
    arg.argc = argc;
    arg.argv = argv;
    return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
    }
    The block call is iterate in ruby

    View Slide

  9. def each(&block)
    @i = 0
    yield @i += 1 until @i >= 10
    end

    View Slide

  10. #loop
    vs
    #while

    View Slide

  11. static VALUE
    loop_i(void)
    {
    for (;;) {
    rb_yield_0(0, 0);
    }
    return Qnil;
    }
    Loop is a method with a block

    View Slide

  12. #enumerator
    Photo by Glenn Carstens-Peters on Unsplash

    View Slide

  13. [].each
    # => #

    View Slide

  14. Why we need Enumerator?

    View Slide

  15. enum = [1, 2, 3].to_enum
    enum.next
    # => 1
    enum.next
    # => 2
    enum.next
    # => 3

    View Slide

  16. Enumerator
    vs
    Enumerable

    View Slide

  17. class Backpack
    include Enumerable
    def initialize(items)
    @items = items
    end
    def each(&block)
    @items.each(&block)
    end
    end
    backpack = Backpack.new([:water, :apple])
    backpack.map {}

    View Slide

  18. #generator
    Photo by m0851 on Unsplash

    View Slide

  19. #to_enum
    vs
    Enumerator.new

    View Slide

  20. class List
    def each(&block)
    #...
    end
    end
    List.new.to_enum
    # => #:each>

    View Slide

  21. class List
    def pop(&block)
    #...
    end
    end
    List.new.to_enum(:pop)
    # => #:pop>

    View Slide

  22. If Enumerator.new didn t have target
    ruby will create a Generator

    View Slide

  23. Enumerator.new do |yielder|
    yielder << 1
    yielder << 2
    end

    View Slide

  24. Why we need Yielder?

    View Slide

  25. enum = Enumerator.new do
    yield 1
    yield 2
    end
    puts enum.to_a
    # => no block given (yield) (LocalJumpError)

    View Slide

  26. class Yielder
    def initialize(&block)
    @proc = block.to_proc
    end
    def <<(value)
    @proc.call(value)
    self
    end
    end

    View Slide

  27. class Generator
    def initialize(&block)
    @proc = block.to_proc
    end
    def each(&_block)
    yielder = Yielder.new { |x| yield x }
    @proc.call(yielder)
    end
    end

    View Slide

  28. #lazy
    Photo by Kate Stone Matheson on Unsplash

    View Slide

  29. It is hard to figure out it, but useful

    View Slide

  30. class Backpack
    def each(&block)
    yield p(1)
    yield p(2)
    yield p(3)
    end
    end
    backpack = Backpack.new.to_enum
    backpack.map(&:rect).take(1).to_a
    backpack.lazy.map(&:rect).take(1).to_a

    View Slide

  31. class Backpack
    def each(&block)
    yield p(1)
    yield p(2)
    yield p(3)
    end
    end
    backpack = Backpack.new.to_enum
    backpack.map(&:rect).take(1).to_a
    backpack.lazy.map(&:rect).take(1).to_a

    View Slide

  32. backpack.map(&:rect).take(1).to_a
    # => 1
    # => 2
    # => 3
    backpack.lazy.map(&:rect).take(1).to_a
    # => 1

    View Slide

  33. backpack.take(1).to_a
    # => 1
    backpack.lazy.take(1).to_a
    # => 1

    View Slide

  34. backpack = Backpack.new.to_enum
    backpack.lazy.reverse_each.take(1).to_a
    # => 1
    # => 2
    # => 3

    View Slide

  35. And last,
    let s discuss implement #lazy in Ruby

    View Slide

  36. Thanks

    View Slide