我可以在Ruby 2.x中获得所需的命名参数吗?

Nat*_*ong 46 ruby arguments ruby-2.0 ruby-2.1

Ruby 2.0正在添加命名参数,如下所示:

def say(greeting: 'hi')
  puts greeting
end

say                     # => puts 'hi'
say(greeting: 'howdy')  # => puts 'howdy'
Run Code Online (Sandbox Code Playgroud)

如何在不提供默认值的情况下使用命名参数,以便它们是必需的?

Mar*_*une 90

在Ruby 2.0.0中没有特定的方法,但你可以使用类似语法的Ruby 2.1.0def foo(a:, b:) ...

在Ruby 2.0.x中,您可以通过放置引发异常的任何表达式来强制执行它,例如:

def say(greeting: raise "greeting is required")
  # ...
end
Run Code Online (Sandbox Code Playgroud)

如果你计划这么做(并且不能使用Ruby 2.1+),你可以使用一个帮助方法,如:

def required
  method = caller_locations(1,1)[0].label
  raise ArgumentError,
    "A required keyword argument was not specified when calling '#{method}'"
end

def say(greeting: required)
  # ...
end

say # => A required keyword argument was not specified when calling 'say'
Run Code Online (Sandbox Code Playgroud)

  • 太好了,你在这教我一些东西,谢谢! (2认同)

Ada*_*dam 19

在当前时刻(Ruby 2.0.0-preview1),您可以使用以下方法签名:

def say(greeting: greeting_to_say)
  puts greeting
end
Run Code Online (Sandbox Code Playgroud)

greeting_to_say只是一个占位符,如果为命名参数提供参数,则不会对其进行求值.如果你没有传入(仅调用say()),ruby将引发错误:

NameError: undefined local variable or method `greeting_to_say' for (your scope)
Run Code Online (Sandbox Code Playgroud)

但是,该变量没有绑定任何东西,据我所知,不能从您的方法内部引用.您仍然可以使用greeting局部变量来引用为命名参数传入的内容.

如果您确实要这样做,我建议您使用,def say(greeting: greeting)以便错误消息引用您为参数指定的名称.我在上面的例子中只选择了不同的,以说明ruby将在错误消息中使用的内容,因为没有为所需的命名参数提供参数.

切线,如果你打电话给say('hi')ruby会加注ArgumentError: wrong number of arguments (1 for 0)我觉得有点混乱,但它只是预览1.

  • 现在我看到它,很明显.它与Ruby 2.0或命名参数完全无关,它与"普通"可选参数的工作方式相同,并且始终具有:`def m(a = b)end; m#NameError:未定义的局部变量或方法'b'表示main:Object`. (4认同)
  • @JörgWMittag太棒了!我没想过. (2认同)

Ben*_*aum 11

结合@awendt和@Adam的解决方案,

def say(greeting: ->{ raise ArgumentError.new("greeting is required") }.call)
  puts greeting
end
Run Code Online (Sandbox Code Playgroud)

你可以通过以下方式来解决这个问题:

def required(arg)
  raise ArgumentError.new("required #{arg}")
end

def say(greeting: required('greeting'))
  puts greeting
end
Run Code Online (Sandbox Code Playgroud)

并将其与@ Marc-Andre的解决方案相结合:https://gist.github.com/rdp/5390849


the*_*tto 6

在 Ruby 2.3 中,我可以做

def say(greeting:)
  puts greeting
end
Run Code Online (Sandbox Code Playgroud)

然后将其与...一起使用

say(greeting: "hello there")
Run Code Online (Sandbox Code Playgroud)