How to mix required argument and optional arguments in ruby?

后端 未结 2 1106
难免孤独
难免孤独 2021-01-14 19:43

I am working on ruby, and the following is my code snippet. I tried mixing required arguments and option arguments. But it gives me an error:

def my_method(a         


        
相关标签:
2条回答
  • 2021-01-14 19:48

    The code you have works just fine in any recent version of Ruby. It won't work in really old versions of Ruby, though, since required positional arguments after splat arguments were only introduced in Ruby 1.9.0.

    A pseudo-regex for parameter lists in Ruby is something like this:

    mand* opt* splat? mand* (mand_kw | opt_kw)* kwsplat? block?
    

    Here's an example:

    def foo(m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
              ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk)
      Hash[local_variables.map {|var| [var, eval(var.to_s)] }]
    end
    
    method(:foo).arity
    # => -5
    
    method(:foo).parameters
    # => [[:req, :m1], [:req, :m2], [:opt, :o1], [:opt, :o2], [:rest, :splat], 
    #     [:req, :m3], [:req, :m4], [:keyreq, :mk1], [:keyreq, :mk2], 
    #     [:key, :ok1], [:key, :ok2], [:keyrest, :ksplat], [:block, :blk]]
    
    foo(1, 2, 3, 4)
    # ArgumentError: missing keywords: mk1, mk2
    
    foo(1, 2, 3, mk1: 4, mk2: 5)
    # ArgumentError: wrong number of arguments (3 for 4+)
    
    foo(1, 2, 3, 4, mk1: 5, mk2: 6)
    # => { m1: 1, m2: 2, o1: :o1, o2: :o2, splat: [], m3: 3, m4: 4, 
    #      ok1: :ok1, mk1: 5, mk2: 6, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, mk1: 6, mk2: 7)
    # => { m1: 1, m2: 2, o1: 3, o2: :o2, splat: [], m3: 4, m4: 5, 
    #      ok1: :ok1, mk1: 6, mk2: 7, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, mk1: 7, mk2: 8)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [], m3: 5, m4: 6, 
    #      ok1: :ok1, mk1: 7, mk2: 8, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, mk1: 8, mk2: 9)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5], m3: 6, m4: 7, 
    #      ok1: :ok1, mk1: 8, mk2: 9, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, mk1: 9, mk2: 10)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: :ok1, mk1: 9, mk2: 10, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: :ok2, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13, k4: 14)
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: nil }
    
    foo(1, 2, 3, 4, 5, 6, 7, 8, 
          ok1: 9, ok2: 10, mk1: 11, mk2: 12, k3: 13, k4: 14) do 15 end
    # => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
    #      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
    #      blk: #<Proc:0xdeadbeefc00l42@(irb):15> }
    
    0 讨论(0)
  • 2021-01-14 19:57

    Array splats (the *p) there are only valid as the last argument in the argument list, since it means "collect all the rest of the arguments passed to the method into an array p".

    Just remove d from the method signature, and in your method, just set d = p.pop and it'll work. Or, move d before *p.

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