检查是否没有传递参数

时间:2014-05-20 17:04:24

标签: ruby arguments

以下是一些代码:

$ 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;
}

2 个答案:

答案 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