ES6 中 Hash 有一个展开操作符 (spread operator) (...) 功能强大,在 ruby 中也有一个类似功能的操作符 (**)
def fun1(**options)
puts "options #{options}"
end
fun1(one: 1, two: 2) # 输出 options {:one=>1, :two=>2}
fun1({one: 1, two: 2}) # 输出 options {:one=>1, :two=>2}
def fun2(one:, two:, **options)
puts "options #{options}"
end
fun2(one: 1, two: 2) # 输出 options {}
fun2(one: 1, two: 2, three: 3) # 输出 options {:three=>3}
fun2(one: 1, two: 2, { three: 3 }) # 输出 SyntaxError: unexpected ')', expecting =>
合并两个 Hash:
a = { one: 1, two: 2 }
b = { two: 22, three: 3 }
{ **a, **b } # = {:one=>1, :two=>22, :three=>3}
还可以这么写:
b = { two: 22, three: 3 }
{ one: 1, two: 2, **b } # = {:one=>1, :two=>22, :three=>3}
require 'benchmark'
n = 5000000
def merge
hash = { one: 1 }
{ two: 2 }.merge(hash)
end
def spread
hash = { one: 1 }
{ two: 2, **hash }
end
Benchmark.bm(2) do |x|
x.report('merge: ') { n.times { merge } }
x.report('spread:') { n.times { spread } }
end
结果:(ruby 2.6.2)(**) 操作符会比 merge 稍稍快一点点
user system total real
merge: 1.640279 0.014161 1.654440 ( 1.800680)
spread: 1.460447 0.010523 1.470970 ( 1.550659)
(**) 操作符只能用在 key 为 symbol 的 Hash
c = { "two" => 22, "three" => 33 }
{ one: 1, two: 2, **c } # TypeError: wrong argument type String (expected Symbol)
另外,在 Rails 中的 controller 里
def fun3(**options); end
object_params = params.permit(:one, :two)
fun3(object_params) # 这样用是不行的 ActionController::UnfilteredParameters - unable to convert unpermitted parameters to hash:
因为 params 不是一个 Hash
fun3(object_params.to_h.symbolize_keys)
这样就可以了