Ruby optional parameters
如果我定义这样的Ruby函数:
1 | def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil ) |
我如何才能称之为只提供前2个和最后一个参数?为什么不是
1 | ldap_get( base_dn, filter, , X) |
可能,或者如果可能,怎么做?
使用选项哈希几乎总是更好的。
1 2 3 4 5 6 | def ldap_get(base_dn, filter, options = {}) options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE ... end ldap_get(base_dn, filter, :attrs => X) |
Ruby目前不可能做到这一点。不能将"空"属性传递给方法。你能得到的最接近的是通过零:
1 | ldap_get(base_dn, filter, nil, X) |
但是,这会将作用域设置为nil,而不是ldap::ldap_scope_子树。
您可以在方法中设置默认值:
1 2 3 4 | def ldap_get(base_dn, filter, scope = nil, attrs = nil) scope ||= LDAP::LDAP_SCOPE_SUBTREE ... do something ... end |
现在,如果您如上所述调用该方法,那么行为将如您所期望的那样。
随着时间的推移,第2版Ruby支持命名参数:
1 2 3 4 5 | 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 | def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE ) |
现在你可以:
1 | ldap_get( base_dn, filter, X ) |
但是现在您有一个问题,您不能用前两个参数和最后一个参数来调用它(与以前的问题相同,但现在最后一个参数不同)。
其基本原理很简单:Ruby中的每个参数都不需要有一个默认值,所以您不能以指定的方式调用它。例如,在您的例子中,前两个参数没有默认值。
1)您不能重载方法(Ruby为什么不支持方法重载?)那么为什么不一起写一个新方法呢?
2)我使用splat操作符*为零或更长的数组解决了类似的问题。然后,如果我想传递一个我可以传递的参数,它被解释为一个数组,但是如果我想调用不带任何参数的方法,那么我不需要传递任何东西。参见Ruby编程语言第186/187页
最近我找到了解决这个问题的方法。我想在数组类中创建一个带有可选参数的方法,以保留或丢弃数组中的元素。
我模拟这个的方法是传递一个数组作为参数,然后检查该索引的值是否为零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
尝试使用不同参数的类方法:
1 2 | 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),会发生什么。
1 2 | 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) |
输出:
如您所见,数组中的第三个选项已被删除,因此在方法中启动一个不同的部分,并删除不在我们范围内的所有ASCII值(32-126)
或者,我们可以在参数中发布值为nil。类似于以下代码块:
1 2 3 4 5 6 | 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 |
您可以使用部分应用程序实现这一点,尽管使用命名变量肯定会导致代码更可读。JohnResig在2008年写了一篇关于如何使用javascript的博客文章:http://ejohn.org/blog/partial-functions-in-javascript/
1 2 3 4 5 6 7 8 9 10 | 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中应用相同的原则是可能的(除了原型继承)。
有可能:)只需更改定义
1 | def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil ) |
到
1 2 | def ldap_get ( base_dn, filter, *param_array, attrs=nil ) scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE |
作用域现在将位于数组的第一位。当您提供3个参数时,那么您将分配基本u dn、filter和attrs,参数u数组将为[]当4个或更多参数时,参数数组将为[参数1或更多,和更多]
缺点是…这是个不清楚的解决方案,真的很难看。这是为了回答在ruby()中函数调用的中间可以使用ommit参数。
您必须做的另一件事是重写范围的默认值。