功能中的多个默认参数不起作用

时间:2015-09-11 18:03:56

标签: ruby function overloading

我试图理解为什么下面的函数会出现编译错误:

# Works fine
def test(a, b=10, c=20)
    p a, b, c
end

# Works fine
def test(a=10, b=20, c)
    p a, b, c
end

# Gives error - syntax error, unexpected '=', expecting ')'
def test(a=10, b, c=20)
    p a, b, c
end

如果多个默认参数都不在参数列表的开头或结尾,则它们似乎不起作用。

2 个答案:

答案 0 :(得分:1)

Ruby允许以灵活的方式定义必需参数和可选参数。这些都是合乎逻辑的:

def foo(a); end 
def foo(a, b); end 
def foo(a, b=1); end
def foo(a=1, b); end
def foo(a=1, b=1); end

如果您需要三个或四个参数,请开始考虑是否应切换到传递参数的其他方式。它是维护和可读性的东西。

而不是任何看起来像

def test(param1=nil, param2, param3, param4, param5, param6, param7, param8, param9, param10) 

在此之前的方式,切换到更简洁的东西。任何这些都是更可取的:

def foo(opts)
  a, b, c = opts.values_at(*%i[a b c]).map{ |v| v.nil? ? 'nil' : v }
  "a: '#{a}' b: '#{b}' c: '#{c}'"
end

foo(a:'a') # => "a: 'a' b: 'nil' c: 'nil'"
foo(a:'a', b:'b') # => "a: 'a' b: 'b' c: 'nil'"
foo(b:'b') # => "a: 'nil' b: 'b' c: 'nil'"
foo(a:'a', b:'b', c: 'c') # => "a: 'a' b: 'b' c: 'c'"

或:

Options = Struct.new('Options', 'a', 'b', 'c')

def foo(opts)
  a, b, c = opts.values.map{ |v| v.nil? ? 'nil' : v }
  "a: '#{a}' b: '#{b}' c: '#{c}'"
end

foo(Options.new('a', nil, 'c')) # => "a: 'a' b: 'nil' c: 'c'"
foo(Options.new('a', 'b', 'c')) # => "a: 'a' b: 'b' c: 'c'"
foo(Options.new(nil, 'b', 'c')) # => "a: 'nil' b: 'b' c: 'c'"

或:

require 'ostruct'

def foo(opts)
  a, b, c = opts.to_h.values_at(*%i[a b c]).map{ |v| v.nil? ? 'nil' : v }
  "a: '#{a}' b: '#{b}' c: '#{c}'"
end

foo(OpenStruct.new(:a => 'a')) # => "a: 'a' b: 'nil' c: 'nil'"
foo(OpenStruct.new(:a => 'a', :b => 'b')) # => "a: 'a' b: 'b' c: 'nil'"
foo(OpenStruct.new(:a => 'a', :b => 'b', :c => 'c')) # => "a: 'a' b: 'b' c: 'c'"

使用这种参数传递可以大大降低噪音。在方法内部,您可以查找未初始化的值并强制其默认值和/或如果您没有收到强制值,则会引发错误。

答案 1 :(得分:0)

this answer related to default parameters翻译参数绑定规则。

  1. 只要参数列表的开头有未绑定的必需参数,就从左到右绑定参数
  2. 只要参数列表末尾有未绑定的必需参数,从右到左绑定参数
  3. 任何剩余的参数都绑定到从左到右的可选参数
  4. 任何剩余的参数都会被收集到一个数组中并绑定到splat参数
  5. 一个块被包装成Proc并绑定到块参数
  6. 如果有任何未绑定参数或剩余参数,raiseArgumentError
  7. 如果我们仔细阅读上述规则,似乎暗示:

      

    如果您在参数列表的开头或结尾没有强制参数,则所有参数都应该是可选的。

    Ruby似乎在以下函数定义中强制执行上述规则:

    # Gives error - syntax error, unexpected '=', expecting ')'
    def test(a=10, b, c=10)
        p a, b, c
    end
    

    如果在开始和结束时确实需要可选参数,可以使用类似下面的内容 - 它在开头使用默认参数,在结尾使用关键字参数。

    def test(a=10, b=20, c, d: 40, e: 40)
        p a, b, c, d, e
    end
    
    test (30)
    #=> 10, 20, 30, 40, 50
    

    但是,以下内容不起作用:

    def test(a=10, b=20, c, d: 40, e: 40, f)
        p a, b, c, d, e
    end
    # Will produce below error
    # syntax error, unexpected tIDENTIFIER
    # def test(a=10, b=20, c, d: 40, e: 40, f)
                                            ^