Difference between block and &block in Ruby

前端 未结 3 1691
执笔经年
执笔经年 2021-01-30 01:47

Why sometimes I should use block and other times &block inside functions that accept blocks?

相关标签:
3条回答
  • 2021-01-30 02:16

    If you don't set the & before block, Ruby won't recognize it's relationship to the "block" you pass to the function. Here some examples.

    def f(x, block); end
    f(3) { 2+2 }    # gives an error, because "block" is a
                    # regular second argument (which is missing)
    
    def g(x, &block); end
    g(3) { 2+2 }    # legal
    
    def h(x); end
    h(3) { 2+2 }    # legal
    

    For later use in a function:

    def x(&block)   # x is a 0 param function
      y(block)      # y is a 1 param function (taking one "Proc")
      z(&block)     # z is a 0 param function (like x) with the block x received
    end
    

    So, if you call z(&block) it's (nearly!!) the same as calling z { yield }: You just pass the block to the next function.

    0 讨论(0)
  • 2021-01-30 02:19

    In an argument list, &whatever takes the block that was passed to the method and wraps it in a Proc object. The Proc is stored in a variable called whatever (where that can be whatever name you typed after the ampersand, of course — usually it's "block"). After a method call, the &whatever syntax turns a Proc into a block. So if you define a method like so:

    def thing(&block)
      thing2 &block
    end
    

    You're defining a method that takes a block and then calls another method with that block.

    0 讨论(0)
  • 2021-01-30 02:23

    block is just a local variable, &block is a reference to the block passed to the method.

    def foo(block = nil)
      p block
    end
    
    foo # => nil
    foo("test") # => test
    foo { puts "this block will not be called" } # => nil
    
    def foo(&block)
      p block
    end
    
    foo # => nil
    foo("test") # => ArgumentError: wrong number of arguments (1 for 0)
    foo { puts "This block won't get called, but you'll se it referenced as a proc." }
    # => #<Proc:0x0000000100124ea8@untitled:20>
    

    You can also use &block when calling methods to pass a proc as a block to a method, so that you can use procs just as you use blocks.

    my_proc = proc {|i| i.upcase }
    
    p ["foo", "bar", "baz"].map(&my_proc)
    # => ["FOO", "BAR", "BAZ"]
    
    p ["foo", "bar", "baz"].map(my_proc)
    # => ArgumentError: wrong number of arguments (1 for 0)
    

    The variable name block doesn't mean anything special. You can use &strawberries if you like, the ampersand is the key here.

    You might find this article helpful.

    0 讨论(0)
提交回复
热议问题