Ruby中具有默认值的可选参数

9
我想创建一个带有可选参数和默认值的函数。
def my_function(a = nil, b=nil, c=500)

end

我想只使用我想要指定的参数来调用该函数。

my_function(b=100)

我该如何在Ruby 1.9.2中实现这个功能?

3个回答

29

参数绑定到参数如下:

  1. 只要在参数列表的开头有未绑定的必需参数,就从左到右绑定参数
  2. 只要在参数列表的末尾有未绑定的必需参数,就从右到左绑定参数
  3. 任何剩余的参数都按从左到右的顺序绑定到可选参数
  4. 任何剩余的参数都被收集到一个数组中,并绑定到分散参数
  5. 块被包装成一个 Proc 并绑定到块参数
  6. 如果有任何未绑定的参数或剩余参数,则引发 ArgumentError

这里是一个例子:

def foo(mand1, mand2, opt1=:opt1, opt2=:opt2, *splat, mand3, mand4, &block)
  p local_variables.map {|v| "#{v} = #{eval(v.to_s)}" }
end

foo 1, 2, 3
# ArgumentError: wrong number of arguments (3 for 4+)

foo 1, 2, 3, 4
# mand1 = 1
# mand2 = 2
# opt1 = opt1
# opt2 = opt2
# splat = []
# mand3 = 3
# mand4 = 4
# block = 

foo 1, 2, 3, 4, 5
# mand1 = 1
# mand2 = 2
# opt1 = 3
# opt2 = opt2
# splat = []
# mand3 = 4
# mand4 = 5
# block = 

foo 1, 2, 3, 4, 5, 6
# mand1 = 1
# mand2 = 2
# opt1 = 3
# opt2 = 4
# splat = []
# mand3 = 5
# mand4 = 6
# block = 

foo 1, 2, 3, 4, 5, 6, 7
# mand1 = 1
# mand2 = 2
# opt1 = 3
# opt2 = 4
# splat = [5]
# mand3 = 6
# mand4 = 7
# block = 

foo 1, 2, 3, 4, 5, 6, 7, 8 do end
# mand1 = 1
# mand2 = 2
# opt1 = 3
# opt2 = 4
# splat = [5, 6]
# mand3 = 7
# mand4 = 8
# block = #<Proc:0x007fdc732cb468@(pry):42>

因此,正如您从上面的第3步和示例中看到的那样,您不能这样做,因为可选参数从左到右绑定,但您想指定中间的参数。

请注意,这对 API 设计有影响:您应该设计参数列表,以便最“不稳定”的可选参数,即用户最可能希望自己提供的参数,位于最左边。

Ruby 2.0 现在具有关键字参数,这正是您要寻找的:

def foo(m1, m2, o1=:o1, o2=:o2, *s, m3, m4, key1: :key1, key2: :key2, **keys, &b)
  puts local_variables.map {|v| "#{v} = #{eval(v.to_s)}" }
end

foo 1, 2, 3
# ArgumentError: wrong number of arguments (3 for 4+)

foo 1, 2, 3, 4
# m1 = 1
# m2 = 2
# o1 = o1
# o2 = o2
# s = []
# m3 = 3
# m4 = 4
# key1 = key1
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = o2
# s = []
# m3 = 4
# m4 = 5
# key1 = key1
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = []
# m3 = 5
# m4 = 6
# key1 = key1
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6, 7
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5]
# m3 = 6
# m4 = 7
# key1 = key1
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6, 7, 8
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5, 6]
# m3 = 7
# m4 = 8
# key1 = key1
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6, 7, 8, key1: 9
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5, 6]
# m3 = 7
# m4 = 8
# key1 = 9
# key2 = key2
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6, 7, 8, key1: 9, key2: 10
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5, 6]
# m3 = 7
# m4 = 8
# key1 = 9
# key2 = 10
# b = 
# keys = {}

foo 1, 2, 3, 4, 5, 6, 7, 8, key1: 9, key2: 10, key3: 11
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5, 6]
# m3 = 7
# m4 = 8
# key1 = 9
# key2 = 10
# b = 
# keys = {:key3=>11}

foo 1, 2, 3, 4, 5, 6, 7, 8, key1: 9, key2: 10, key3: 11, key4: 12 do end
# m1 = 1
# m2 = 2
# o1 = 3
# o2 = 4
# s = [5, 6]
# m3 = 7
# m4 = 8
# key1 = 9
# key2 = 10
# b = #<Proc:0x007fdc75135a48@(pry):77>
# keys = {:key3=>11, key4=>12}

8
您不能在 Ruby < 2.0 中这样做(或类似的操作)。最好的方法是:
def my_function(h = {})
  h[:c] ||= 500
  # Use h[:a], h[:b], h[:c]
  ...
end

my_function(b: 100)

2
这是错误的。你可以有任意多个可选参数,它们不必是最后一个。def foo(mand1, mand2, opt1=:opt1, opt2=:opt2, *splat, mand3, mand4, &block) p local_variables.map {|v| "#{v} = #{eval(v.to_s)}" } end 是完全正确的。 - Jörg W Mittag
1
@JörgWMittag 对的,我错了。我会删除那部分内容。 - sawa
@JörgWMittag 我认为一些旧版本的Ruby确实要求具有默认值的参数,如果不是最后一个,则至少在所有“普通”参数之后。 - Wayne Conrad
啊,是的。看起来Ruby 1.9引入了在非默认参数之前设置默认值的功能。 - Wayne Conrad

8

所以你想要实现关键字参数?这应该是 Ruby 2.0 的新功能,但你可以尝试使用参数哈希在 1.9.x 中模拟它。 这篇文章讨论了如何实现关键字参数,并提供以下代码示例:

def foo(options = {})
  options = {bar: 'bar'}.merge(options)
  puts "#{options[:bar]} #{options[:buz]}"
end

foo(buz: 'buz') # => 'bar buz'

11
不要创建只包含指向答案的链接的回答。当该链接失效时,你的回答将会变得无用。相反,应该概括那个答案的相关部分。 - the Tin Man
3
链接已失效。 - NM Pennypacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接