5

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

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

有没有办法确定用户是否在arg2方法中传递了一个值?显然我可以添加if arg2 == "bar"到方法中,但这并没有捕捉到用户"bar"自己手动传递的情况。当然,我可以将默认值设置为任何用户都不会传入的默认值,但很快就会变得非常难看。

有什么优雅的地方吗?

4

5 回答 5

17
def foo(arg1, arg2 = (arg2_not_passed = true; "bar"))
  puts arg1
  puts arg2
  puts 'arg2 was passed' unless arg2_not_passed
end
于 2013-10-20T08:06:49.487 回答
3
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
于 2013-10-20T00:11:22.960 回答
3

一种方法(不优雅但有趣)是使默认值具有唯一的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"
于 2013-10-20T00:57:26.420 回答
2

我有办法!假设我们想要:

def foo(arg1, arg2 = 42)

然后我们改为写:

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

如果agr2 == [42,KEY],我们得出结论,调用方法没有传递第二个参数,在这种情况下,42应用默认值 。如果arg2是别的,arg2就通过了。简单的!

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

我想再补充一件事。我原则上反对这样做,但我知道如果我不这样做,我会收到如此多的反对票,以至于我的名声会变成负面的。所以这里是:-)

于 2013-10-20T04:47:25.930 回答
1

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

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

然后尝试调用method以下实例Test

?> 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 的工作原理。

于 2013-10-20T00:26:37.200 回答