Ruby方法和多个默认值的排序

时间:2010-03-03 12:12:49

标签: ruby

我似乎无法做到这一点(我以前在Python中可以做到这一点)。让我解释..

假设我在Ruby中有以下方法:

def someMethod(arg1=1,arg2=2,arg3=3)
...
...
...
end

现在调用这个方法我可以做

someMethod(2,3,4)
someMethod(2,3)
someMethod(2)

并且参数是按各自的顺序进行的..但是如果我想在编程中的某个时刻给出arg2并且想要arg1和arg3的默认值呢?

我尝试编写someMethod(arg2 = 4),但这似乎不适用于Ruby 1.9。它做的是它仍然认为arg1是4.在python我至少可以逃脱这个,但在红宝石中我不确定。有没有人有任何优雅的想法?

3 个答案:

答案 0 :(得分:13)

现在只有优雅的解决方案是使用hash作为参数列表:

def some_method(options = {})
  defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3}
  options = defaults.merge(options)
  ...
end

以后代码在调用方法时使用隐式哈希:

some_method()
some_method(:arg1 => 2, :arg2 => 3, :arg3 => 4)
some_method(:arg2 => 4)

在Ruby 1.9中,您可以使用新的哈希键语法来更像Python:

some_method(arg1: 2, arg2: 3, arg3: 4)

如果你想要更简单的语法并且仍然能够使用位置参数,那么我建议你玩这样的东西:

def some_method(*args)
  defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3}
  options = args.last.is_a?(::Hash) ? args.pop : {}
  options = defaults.merge(options)

  arg1 = args[0] || options[:arg1]
  arg2 = args[1] || options[:arg2]
  arg3 = args[2] || options[:arg3]
  ...
end

some_method()
some_method(2)
some_method(3,4,5)
some_method(arg2: 5)
some_method(2, arg3: 10)

如果您想模仿方法的Ruby参数号检查,可以添加:

fail "Unknown parameter name(s) " + (options.keys - defaults.keys).join(", ") + "." unless options.length == defaults.length

编辑:
我用Jonas Elfström的评论

更新了我的答案

答案 1 :(得分:2)

对于你想要做的事情,最好的方法是使用Hash作为唯一的参数。

def someMethod(args={})
args[:arg1] ||= 1
args[:arg2] ||= 2
args[:arg3] ||= 3
...

然后将像这样调用此方法

someMethod(:arg1 => 2, :arg3 => 5)

未设置的所有哈希值都将被其默认值替换(例如arg2 = 2)。

答案 2 :(得分:2)

Ruby没有关键字参数传递。 (还没有,无论如何,它是可能成为Ruby 2.0的东西之一。但是,没有任何保证,并且Ruby 2.0的工作甚至还没有启动,所以没有任何说法什么时候或者甚至我们会在Ruby中看到关键字参数。)

真正发生的是:您将表达式arg2 = 4作为参数列表中的唯一参数传递。 Ruby是一种带有pass-by-value的严格语言,这意味着所有参数在传递给方法之前都要完全评估。在这种情况下,arg2 = 4是一个赋值表达式(在Ruby中,所有是一个表达式(即一切都返回一个值),没有语句)。您要将直接文字Fixnum4分配给本地变量arg2。赋值表达式始终返回其右侧的值,在本例中为4

所以,你将值4作为唯一的参数传递给你的方法,这意味着它被绑定到第一个必需参数(如果有的话)(在这种情况下,没有),否则到第一个可选参数(在本例中为arg1)。

处理这种情况的常用方法是使用Hash代替,如下所示:

some_method({:arg2 => 4})

因为经常使用这种模式,所以有一种特殊的语法支持:如果方法的 last 参数是Hash,你可以不用花括号:

some_method(:arg2 => 4)

在Ruby 1.9中,还有另一种语法便利形式:因为Hash经常与Symbol键一起使用,所以有一种替代的Hash字面语法:

some_method({arg2: 4})

将两者结合起来,几乎都有关键字参数:

some_method(arg2: 4)

(事实上,这两个快捷方式都是专门添加的,以便为使用关键字参数的Ruby的未来版本提供简单的迁移路径。)

MacRuby实际上支持Smalltalk样式的多部分消息选择器,以实现与Objective-C的互操作性。但请注意,Smalltalk样式的多部分消息选择器是不是关键字参数,它们的行为方式非常不同。当然,这个扩展特定于MacRuby而不是Ruby规范的一部分,不能移植到MRI,YARV,JRuby,XRuby,IronRuby,MagLev,Rubinius,tinyrb,RubyGoLightly,BlueRuby,SmallRuby或任何其他Ruby实现。< / p>