236

你见过这样声明的函数吗?

def foo a, **b
  ...
end

我知道单*是 splat 运算符。是什么**意思?

4

3 回答 3

413

Ruby 2.0 引入了关键字参数,其**行为类似于*, 但用于关键字参数。它返回一个带有键/值对的哈希。

对于此代码:

def foo(a, *b, **c)
  [a, b, c]
end

这是一个演示:

> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]
于 2013-08-17T13:11:15.387 回答
48

这是从 Ruby 2.0 开始可用的双 splat运算符。

它捕获所有关键字参数(也可以是简单的哈希,这是在关键字参数成为 Ruby 语言的一部分之前模拟关键字参数的惯用方式)

def my_method(**options)
  puts options.inspect
end

my_method(key: "value")

上面的代码打印{key:value}到控制台。

就像单个 splat 运算符捕获所有常规参数一样,但得到的不是数组,而是hash

现实生活中的例子:

例如在 Rails 中,该cycle方法如下所示:

def cycle(first_value, *values)
  options = values.extract_options!
  # ...
end

这个方法可以这样调用:cycle("red", "green", "blue", name: "colors").

这是一种非常常见的模式:您接受参数列表,最后一个是选项哈希,可以提取 - 例如 - 使用 ActiveSupport 的extract_options!.

在 Ruby 2.0 中,您可以简化这些方法:

def cycle(first_value, *values, **options)
  # Same code as above without further changes!
end

诚然,如果您已经在使用 ActiveSupport,这只是一个很小的改进,但对于纯 Ruby,代码获得了相当多的简洁性。

于 2013-08-17T13:11:31.810 回答
32

此外,您可以像这样在调用方使用它:

def foo(opts); p opts end
bar = {a:1, b:2}

foo(bar, c: 3)
=> ArgumentError: wrong number of arguments (given 2, expected 1)

foo(**bar, c: 3)
=> {:a=>1, :b=>2, :c=>3}
于 2017-07-26T22:50:08.327 回答