Ruby可选参数


121

如果我定义这样的Ruby函数:

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

我怎么称呼它只提供前两个和最后一个参数?为什么不像

ldap_get( base_dn, filter, , X)

可能,或者如果可能,怎么办?

Answers:


131

目前,这对于红宝石是不可能的。您不能将“空”属性传递给方法。您可以获得的最接近的结果是传递nil:

ldap_get(base_dn, filter, nil, X)

但是,这会将范围设置为nil,而不是LDAP :: LDAP_SCOPE_SUBTREE。

您可以做的是在方法中设置默认值:

def ldap_get(base_dn, filter, scope = nil, attrs = nil)
  scope ||= LDAP::LDAP_SCOPE_SUBTREE
  ... do something ...
end

现在,如果您按上述方式调用方法,其行为将与您预期的一样。


21
这种方法有点麻烦:例如,如果您尝试将默认值设置为scopetrue并传入falsescope ||= true则将无法使用。它的评估结果相同nil,并将其设置为true
Joshua Pinter

4
在此答案的3年后,当前版本的ruby是否有可能?
dalloliogm 2012年

1
@JoshPinter,很好的解释。基本上,|| =不是a = b或c,我很乐意看到xyz||=true。这是说如果它为零,那总是对的。如果是真的,那是真的。
达蒙·奥

7
众人都说这有多么糟糕scope ||= true,我很惊讶没有人提到使用来实现此目标的更好方法scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?。当然,即使那是假定这nil是一个无效值。
埃里克·桑德伯格

1
更新此旧歌:一种替代方法是使用下划线符号。不幸的是,它具有与将参数设置为相同的效果nil。有些人可能喜欢这种表示法:(ldap_get(base_dn, filter, _, X)注意:我还不知道(何时)在Ruby中引入它的。有趣的SO线程)。
埃里克·普拉顿

137

使用选项哈希几乎总是更好。

def ldap_get(base_dn, filter, options = {})
  options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE
  ...
end

ldap_get(base_dn, filter, :attrs => X)

23
常见的策略是使用默认选项哈希并合并传入的任何内容:options = default_options.merge(options)
Nathan Long

7
我劝阻这是因为选择不告诉你什么方法需要还是什么的默认值是
勒布朗·戴维斯

53

时间已经过去,自版本2开始,Ruby支持命名参数:

def ldap_get ( base_dn, filter, scope: "some_scope", attrs: nil )
  p attrs
end

ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2"

1
您还可以使用double splat来收集其他未定义的关键字参数。这与此问题有关:stackoverflow.com/a/35259850/160363
曾亨利(Henry Tseng)

3

无法按照您定义的方式进行操作ldap_get。但是,如果您这样定义ldap_get

def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE )

现在你可以:

ldap_get( base_dn, filter, X )

但是现在您有一个问题,您不能使用前两个arg和最后一个arg来调用它(与以前一样,但是现在最后一个arg不同)。

这样做的理由很简单:Ruby中的每个参数都不需要具有默认值,因此您不能以指定的方式调用它。例如,在您的情况下,前两个参数没有默认值。


1

1)您不能重载该方法(ruby为什么不支持方法重载?)为什么不完全编写一个新方法?

2)我使用splat运算符*解决了一个零个或多个长度数组的类似问题。然后,如果我想传递一个(或多个)参数,它会被解释为一个数组,但是如果我想在不带任何参数的情况下调用该方法,则不必传递任何东西。请参见Ruby编程语言第186/187页


0

最近,我找到了解决此问题的方法。我想在数组类中创建一个带有可选参数的方法,以保留或丢弃数组中的元素。

我模拟此方法的方式是通过将数组作为参数传递,然后检查该索引处的值是否为nil。

class Array
  def ascii_to_text(params)
    param_len = params.length
    if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end
    bottom  = params[0]
    top     = params[1]
    keep    = params[2]
    if keep.nil? == false
      if keep == 1
        self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
      else
        raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil"
      end
    else
      self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
    end
  end
end

尝试使用具有不同参数的类方法:

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for)

输出: ["1", "2", "a", "b", "c"]

好的,很酷,可以按计划工作。现在让我们检查一下,如果不传入数组中的第三个参数选项(1),会发生什么情况。

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option)

输出: ["a", "b", "c"]

如您所见,数组中的第三个选项已删除,因此在方法中启动了另一部分,并删除了不在我们范围内的所有ASCII值(32-126)

或者,我们可以在参数中将值发布为nil。看起来类似于以下代码块:

def ascii_to_text(top, bottom, keep = nil)
  if keep.nil?
    self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
  else
    self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
end

-1

有可能:)只需更改定义

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

def ldap_get ( base_dn, filter, *param_array, attrs=nil )
scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE

范围现在将排在第一位。当您提供3个参数时,您将分配base_dn,filter和attrs,并且param_array将为[]当4个或更多参数时,param_array将为[argument1,or_more和_more]

缺点是...这是不清楚的解决方案,真的很难看。这是为了回答有可能在ruby的函数调用中间省略参数:)

您要做的另一件事是重写scope的默认值。


4
这种解决方案是完全错误的。attrs=nil在splat(*param_array)之后使用默认值参数()是语法错误。
埃里克·桑德伯格

3
-1:Erik是正确的。在irb 2.0.0p247中引起语法错误。根据Ruby编程语言的规定,在Ruby 1.8中,splat参数必须是最后一个&parameter,除了之外,但在Ruby 1.9中,它也可以跟在“常规参数”之后。在这两种情况下,带有斜线的参数之后的默认合法参数都不是。
andyg0808 2013年

Ruby编程语言第186/187页splat非常适合与方法一起使用。除非使用&,否则它必须是方法中的最后一个参数。
rupweb 2014年

因此AndyG是对的,其顺序应为:def ldap_get(base_dn,filter,attrs = nil,* param_array)
rupweb 2014年

-1

您可以使用部分应用程序执行此操作,尽管使用命名变量肯定会导致更具可读性的代码。John Resig在2008年撰写了一篇有关如何使用JavaScript的博客文章:http : //ejohn.org/blog/partial-functions-in-javascript/

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

在Ruby中可能会应用相同的原理(原型继承除外)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.