以下是一些代码:
$ cat 1.rb
#!/usr/bin/env ruby
def f p1 = nil
unless p1 # TODO
puts 'no parameters passed'
end
end
f
f nil
$ ./1.rb
no parameters passed
no parameters passed
问题是,有没有办法区分没有参数和一个nil
参数传递?
UPD
我决定在javascript
中添加一个用例,以使事情更加清晰:
someProp: function(value) {
if (arguments.length) {
this._someProp = value;
}
return this._someProp;
}
答案 0 :(得分:10)
一般使用三种方法。一种方法是使用默认值设置另一个变量,指示是否评估了默认值:
def f(p1 = (no_argument_passed = true; nil))
'no arguments passed' if no_argument_passed
end
f # => 'no arguments passed'
f(nil) # => nil
第二种方法是使用一些仅在方法内部已知的对象作为默认值,以便局外人无法传递该对象:
-> {
undefined = BasicObject.new
define_method(:f) do |p1 = undefined|
'no arguments passed' if undefined.equal?(p1)
end
}.()
f # => 'no arguments passed'
f(nil) # => nil
在这两个中,第一个更具惯用性。第二个(实际上是它的变体)在Rubinius中使用,但我从未在其他地方遇到过它。
第三种解决方案是使用splat来获取可变数量的参数:
def f(*ps)
num_args = ps.size
raise ArgumentError, "wrong number of arguments (#{num_args} for 0..1)" if num_args > 1
'no arguments passed' if num_args.zero?
end
f # => 'no arguments passed'
f(nil) # => nil
请注意,这需要您手动重新实现Ruby的arity检查。 (我们仍然没有把它弄好,因为这会引发内部方法的异常,而Ruby会在调用网站处引发它。)它还需要您可以手动记录方法签名,因为自动文档生成器(如RDoc或YARD)将推断出任意数量的参数而不是单个可选参数。
答案 1 :(得分:5)
您可以请求splat参数:
def f(*args)
if args.empty?
puts 'no parameters passed'
else
p1 = args[0]
...
end
end
其他一些选项可能是让私有对象指示没有传递参数:
def initialize
@no_param_passed = Object.new
end
def f(p1 = @no_param_passed)
if p1 == @no_param_passed
puts 'no parameters passed'
end
end