If I define a Ruby functions like this:
def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )
如何仅使用前两个参数和最后一个参数进行调用?为什么不能使用以下方式调用:
ldap_get( base_dn, filter, , X)
是否可能,如果可能的话,该如何实现?
If I define a Ruby functions like this:
def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )
如何仅使用前两个参数和最后一个参数进行调用?为什么不能使用以下方式调用:
ldap_get( base_dn, filter, , X)
是否可能,如果可能的话,该如何实现?
使用选项哈希通常更好。
def ldap_get(base_dn, filter, options = {})
options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE
...
end
ldap_get(base_dn, filter, :attrs => X)
目前 Ruby 不支持此功能。您无法向方法传递“空”属性。最接近的方法是传递 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
现在,如果按照上述方法调用该方法,则行为将与您期望的一样。
scope
的默认值为true
,并传入了false
,那么scope ||= true
就不能正常工作。它会被认为是nil
,然后被赋值为true
。 - Joshua Pinterxyz ||= true
我感到不舒服。它的意思是如果它是nil,它总是true。如果它是true,那么它就是true。 - Damon Awscope ||= true
很糟糕时,我很惊讶没有人提到更好的方法是使用scope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?
。当然,前提是假定nil
是无效值。 - Erik Sandbergldap_get(base_dn, filter, _, X)
(注意:我还不知道这是何时引入Ruby的。有趣的SO线程)。 - Eric Platon时间已经过去,自从版本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"
按照你定义的方式,无法实现ldap_get
。但是,如果你像这样定义ldap_get
:
def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE )
ldap_get( base_dn, filter, X )
但是现在你遇到了一个问题,你不能使用前两个参数和最后一个参数来调用它(与之前的问题相同,但现在最后一个参数不同)。
这背后的原理很简单:Ruby中的每个参数都不需要有默认值,因此您无法按照指定的方式调用它。例如,在您的情况下,前两个参数没有默认值。
1) 你不能重载方法(为什么Ruby不支持方法重载?),那么为什么不完全编写一个新的方法呢?
2) 我使用了零个或多个长度的数组的扩展运算符*解决了类似的问题。然后,如果我想传递一个或多个参数,它会被解释为一个数组,但如果我想调用没有任何参数的方法,则不需要传递任何内容。请参见Ruby编程语言第186/187页。
最近我找到了一个解决方法。我想在数组类中创建一个带有可选参数的方法,以保留或丢弃数组中的元素。
我模拟的方法是通过将数组作为参数传递,并检查该索引处的值是否为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
可以的 :) 只需要改变定义
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,and_more]
缺点是...这是一个不清晰的解决方案,非常丑陋。这是为了回答在Ruby函数调用中可能省略参数的问题 :)
另一件事情是要重写作用域的默认值。
*param_array
)后,在默认值参数(attrs=nil
)中设置默认值是语法错误。 - Erik Sandberg¶meter
,但在 Ruby 1.9 中,它也可以跟在“普通参数”之后。在任何情况下,带有默认值的参数都不能在星号参数之后声明。 - andyg0808你可以使用部分应用来实现这个,但是使用命名变量肯定会导致更易读的代码。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 中应用相同的原则可能是可行的(除了原型继承)。
options = default_options.merge(options)
。 - Nathan Long