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

如何确定Ruby中是否传递了可选参数,ruby,parameters,optional-parameters,Ruby,Parameters,Optional Parameters,如果我在Ruby中有以下方法: def foo(arg1, arg2 = "bar") puts arg1 puts arg2 end 是否有办法确定用户是否在方法中为arg2传递了值?显然,如果arg2==“bar”,我可以只向方法中添加,但这不包括用户自己手动输入“bar”的情况。当然,我可以将默认设置为任何用户都不会传入的内容,但很快就会变得非常糟糕 外面有什么优雅的东西吗?我不确定这是否可行。考虑以下事项: def foo(*args) case args.length

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

def foo(arg1, arg2 = "bar")
  puts arg1
  puts arg2
end
是否有办法确定用户是否在方法中为
arg2
传递了值?显然,如果arg2==“bar”,我可以只向方法中添加
,但这不包括用户自己手动输入
“bar”
的情况。当然,我可以将默认设置为任何用户都不会传入的内容,但很快就会变得非常糟糕


外面有什么优雅的东西吗?

我不确定这是否可行。考虑以下事项:

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
class Test
  def method(a,b=1)
    local_variables.each do |var|
          puts "Setting #{var} to #{eval var.to_s}"
    end
  end
end
raise ArgumentError, "Too many arguments" if args.length > 2
然后尝试在
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的方法结合以下内容:

class Test
  def method(a,b=1)
    local_variables.each do |var|
          puts "Setting #{var} to #{eval var.to_s}"
    end
  end
end
raise ArgumentError, "Too many arguments" if args.length > 2
因为您似乎希望将参数限制为2,@sawa的方法允许使用未定义的数字

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

一种方法(不是优雅而是有趣)是设置默认值,使其具有唯一的
对象id
。如果默认值是不可变的对象(如integer),则它将不起作用

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(1000000000000)


我想补充一点。原则上,我反对这样做,但我知道如果我不这样做,我会收到太多的反对票,我的声誉将受到负面影响。所以这里是::-)

我的理解正确吗,例如,您想知道
foo
是否可以确定对它的调用是
foo(arg1)
还是
foo(arg1,“bar”)
?是的,就是这样。感谢您提供的详细信息。在我的实际实现中,我只是将第二个参数默认为
nil
(因为用户永远不会将
nil
传递给它),然后在方法中用“default”值交换
nil
,但我很好奇是否有更好的方法。我不明白为什么要反复使用
局部变量,而不仅仅是引用
a
b
。不管怎样,这不就是我们已经知道的吗?我喜欢!这就是Rubinius在许多方法实现中所做的。在YARV、JRuby等中,它们是用C、Java等实现的,可以访问参数列表的内部实现,因此可以检查传递了多少个参数。但是在Rubinius中,这些方法中的许多都是用纯Ruby实现的,没有任何特殊的功能,因此它们不得不求助于这样的技巧。在Rubinius中,有一个特殊的
undefined
方法,该方法返回一个具有不可伪造
object\u id
的对象,然后在该方法中执行
undefined.equals?(b)
。有趣;如果您能帮助理解
a=(b=true;“something”)
这只是一个Ruby表达式,我将不胜感激。它首先将
b
设置为
true
,然后作为新语句执行字符串
“something”
。整个括号的值将是最后一条语句的值,因此它仍然会按预期将
a
设置为
“something”
。我相信你希望这是
arg2=(arg2\u was\u passed=false;“bar”)
,但不是
true
。这是天才!我只是想了一下类似的方法,发现你已经回答了。我想知道你为什么反对使用这种方法。例如,编写像
def mymethod(param1,param2=“未由用户指定”)
这样的方法有什么坏处?如果param2==“未由用户指定”
,则我可以在正文中使用param2=“default value”。原则上我没有异议(尽管其他人可能会反对)。我只是觉得这有点含糊不清,最好是重新构造代码,避免回答这个问题。