Ruby 中具有默认值的可选参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16322706/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Optional arguments with default value in Ruby
提问by AdamNYC
I would like to create a function that has optional arguments with default values
我想创建一个具有默认值的可选参数的函数
def my_function(a = nil, b=nil, c=500)
end
and call the function with the arguments I would like to specify only
并使用我只想指定的参数调用函数
my_function(b=100)
How do I accomplish this in Ruby 1.9.2?
我如何在 Ruby 1.9.2 中实现这一点?
回答by J?rg W Mittag
Arguments are bound to parameters like this:
参数绑定到这样的参数:
- As long as there are unbound mandatory parameters at the beginning of the parameter list, bind arguments left-to-right
- As long as there are unbound mandatory parameters at the end of the parameter list, bind arguments right-to-left
- Any leftover arguments are bound to optional parameters left-to-right
- Any leftover arguments are collected into an array and bound to the splat argument
- A block is wrapped up into a
Procand bound to the block argument - If there are any unbound parameters or leftover arguments,
raiseanArgumentError
- 只要参数列表开头有未绑定的强制参数,从左到右绑定参数
- 只要参数列表末尾有未绑定的强制参数,从右到左绑定参数
- 任何剩余的参数都从左到右绑定到可选参数
- 任何剩余的参数都被收集到一个数组中并绑定到 splat 参数
- 一个块被包装成 a
Proc并绑定到块参数 - 如果有任何未绑定的参数或吃剩的参数,
raise一个ArgumentError
Here's an example:
下面是一个例子:
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>
So, as you can see both from step 3 above and from the example, you cannot do this, because optional parameters are bound left-to-right, but you want to specify the middle argument.
因此,正如您从上面的第 3 步和示例中所见,您不能这样做,因为可选参数是从左到右绑定的,但您想指定中间参数。
Note that this has implications on API design: you should design your parameter lists in such a way that the most "unstable" optional parameters, i.e. the ones that a user most likely wants to supply themselves, are furthest to the left.
请注意,这对 API 设计有影响:您应该以最“不稳定”的可选参数(即用户最有可能希望自己提供的参数)最靠左的方式设计参数列表。
Ruby 2.0 now has keyword arguments, which is exactly what you are looking for:
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}
回答by hlh
So you're trying to implement keyword arguments? This is supposed to be a new feature in Ruby 2.0, but you can try to mimic it in 1.9.x with a hash of arguments instead. Here's a postthat discusses how you can accomplish that, which gives the following code sample:
所以你想实现关键字参数?这应该是 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'
回答by sawa
You cannot do that (or something similar) in Ruby < 2.0. The best you could do is:
在 Ruby < 2.0 中你不能这样做(或类似的事情)。你能做的最好的是:
def my_function(h = {})
h[:c] ||= 500
# Use h[:a], h[:b], h[:c]
...
end
my_function(b: 100)

