如何确定Ruby中是否传递了可选参数

如果我在Ruby中有以下方法:

def foo(arg1, arg2 = "bar") puts arg1 puts arg2 end 

有没有办法确定用户是否在方法中传递了arg2的值? 显然我可以在方法中添加if arg2 == "bar" ,但这并不能解决用户自己手动传入"bar" 。 当然,我可以将默认设置为没有用户可以传递的内容,但是那很快就变得非常难看。

那里有什么优雅的东西吗?

我不确定这是可能的。 考虑以下:

 class Test def method(a,b=1) local_variables.each do |var| puts "Setting #{var} to #{eval var.to_s}" end end end 

然后尝试在Test实例上调用method

 ?> t.method(1) Setting a to 1 Setting b to 1 => [:a, :b] ?> t.method(1,2) Setting a to 1 Setting b to 2 => [:a, :b] ?> t.method(1,1) Setting a to 1 Setting b to 1 => [:a, :b] 

那些不区分方法的调用方式。

所以我建议@ sawa的方法与以下内容混合:

 raise ArgumentError, "Too many arguments" if args.length > 2 

因为你似乎想要将参数限制为2,而@ sawa的方法允许使用未定义的数字。

对于非正统的要求,这是一种非正统的方法,因此请确保您的方法的客户端了解API的工作原理。

 def foo(arg1, arg2 = (arg2_not_passed = true; "bar")) puts arg1 puts arg2 puts 'arg2 was passed' unless arg2_not_passed end 
 def foo(*args) case args.length when 1 # arg2 was not given arg1, arg2 = args.first, "bar" ... when 2 # arg2 was given arg1, arg2 = args ... else raise ArgumentError end end 

一种方式(不优雅但有趣)是使默认值具有唯一的object_id 。 如果默认值是整数等不可变对象,它将无法工作。

 def c @c ||= "bar" end def fun(a,b = c) puts b.object_id == c.object_id ? "default" : "user" end fun "foo" #=> "default" fun "foo", "bar" #=> "user" 

我有一个解决方案! 假设我们想要:

 def foo(arg1, arg2 = 42) 

然后我们会写:

 def foo(arg1, arg2 = [42,KEY]) 

如果agr2 == [42,KEY] ,我们得出结论,调用方法没有传递第二个参数,在这种情况下,默认值为42 。 如果arg2是其他任何东西,则传递arg2 。 简单!

我知道你在想什么:如果调用程序真的通过了[42,KEY]怎么办? 我也想到了这一点: KEY = rand(100000000000000)

我想补充一点。 我原则上反对这样做,但我知道如果我不这样做,我会收到这么多的支持,我的名声将会消极。 所以这里是::-)