检查是否没有传递参数

x-y*_*uri 6 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
Run Code Online (Sandbox Code Playgroud)

问题是,有没有办法区分没有参数和一个nil参数传递?

UPD

我决定添加一个用例,javascript以使事情更加清晰:

someProp: function(value) {
    if (arguments.length) {
        this._someProp = value;
    }
    return this._someProp;
}
Run Code Online (Sandbox Code Playgroud)

Jör*_*tag 10

一般使用有三种方法.一种方法是使用默认值设置另一个变量,指示是否评估了默认值:

def f(p1 = (no_argument_passed = true; nil))
  'no arguments passed' if no_argument_passed
end

f      # => 'no arguments passed'
f(nil) # => nil
Run Code Online (Sandbox Code Playgroud)

第二种方法是使用一些仅在方法内部已知的对象作为默认值,这样外人就不可能将该对象传递给:

-> {
  undefined = BasicObject.new
  define_method(:f) do |p1 = undefined|
    'no arguments passed' if undefined.equal?(p1)
  end
}.()

f      # => 'no arguments passed'
f(nil) # => nil
Run Code Online (Sandbox Code Playgroud)

在这两个中,第一个更惯用.第二个(实际上,它的变体)在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
Run Code Online (Sandbox Code Playgroud)

请注意,这需要您手动重新实现Ruby的arity检查.(我们仍然没有得到它的权利,因为这引发异常里面的方法,而红宝石将在提高它调用站点.)这也需要您手动记录您的方法签名,因为自动记录生成如RDoc的或者YARD将推断任意数量的参数而不是单个可选参数.


Uri*_*ssi 5

您可以请求splat参数:

def f(*args)
  if args.empty?
    puts 'no parameters passed'
  else
    p1 = args[0]
    ...
  end
end
Run Code Online (Sandbox Code Playgroud)

其他一些选项可能是让私有对象指示没有传递参数:

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
Run Code Online (Sandbox Code Playgroud)