【问题标题】:Hash Destructuring哈希解构
【发布时间】:2013-02-17 22:32:44
【问题描述】:

您可以使用 splat 运算符解构数组。

def foo(arg1, arg2, arg3)
  #...Do Stuff...
end
array = ['arg2', 'arg3']
foo('arg1', *array)

但是有没有办法为了选项类型的优点而破坏哈希?

def foo(arg1, opts)
  #...Do Stuff with an opts hash...
end
opts = {hash2: 'bar', hash3: 'baz'}
foo('arg1', hash1: 'foo', *opts)

如果不是原生 ruby​​,Rails 是否添加了类似的东西?

目前我正在大致这样做

foo('arg1', opts.merge(hash1: 'foo'))

【问题讨论】:

  • 如果你在谈论默认选项,是的merge 是要走的路。
  • 你有什么理由颠倒订单而不是做{hash1: 'foo'}.merge(opts)
  • @sawa 不是。就是自然产生的结果。

标签: ruby hash splat


【解决方案1】:

是的,有一种方法可以解构哈希:

def f *args; args; end
opts = {hash2: 'bar', hash3: 'baz'}
f *opts  #=> [[:hash2, "bar"], [:hash3, "baz"]]

问题是你想要的实际上是不是解构。你正试图离开

'arg1', { hash2: 'bar', hash3: 'baz' }, { hash1: 'foo' }

(记住'arg1', foo: 'bar' 只是'arg1', { foo: 'bar' } 的简写)到

'arg1', { hash1: 'foo', hash2: 'bar', hash3: 'baz' }

根据定义,合并(注意周围的结构——散列——仍然存在)。而解构是从

'arg1', [1, 2, 3]

'arg1', 1, 2, 3

【讨论】:

【解决方案2】:

现在是 2018 年,值得更新。 Ruby 2.0 introduced keyword arguments 以及哈希 splat 运算符 **。现在您可以简单地执行以下操作:

def foo(arg1, opts)
  [arg1, opts]
end

opts = {hash2: 'bar', hash3: 'baz'}
foo('arg1', hash1: 'foo', **opts)
#=> ["arg1", {:hash1=>"foo", :hash2=>"bar", :hash3=>"baz"}]

【讨论】:

  • 请记住,这只适用于符号键。 {**{a: 1}, **{b: 2}} #=> {:a=>1, :b=>2}{**{'a' => 1}, **{'b' => 2}} #=> TypeError (wrong argument type String (expected Symbol))
  • 是的。我希望在 model.as_json 调用中添加一些键并使用 Rails 的 symbolize_keys 方法:hash = {a: 1, b: 2, **model.as_json.symbolize_keys}
【解决方案3】:

没有这样的事情(尽管已经提出)。由于这会改变解析规则,它不能在 Ruby 中实现。我能想到的最好的方法是在哈希上定义*

class Hash; alias :* :merge end

并以下列方式之一使用它:

foo('arg1', {hash1: 'foo'}*opts)
foo('arg1', {hash1: 'foo'} *opts)
foo('arg1', {hash1: 'foo'}. *opts)

我认为最后一个与您想要的相当接近。

【讨论】:

  • 也许使用+ 代替* 会更有意义?
  • @AndrewMarshall 我同意这一点。我想让它看起来更接近 splat 运算符。
  • 现在可以在 Ruby 3 中使用,但使用了不同/新的语法:{a: 1, b: 2, c: 3, d: 4} => {a:, b:, **rest}(参见ruby3.dev/ruby-3-fundamentals/2021/01/06/…
【解决方案4】:

如果您可以使用 active_support:

require 'active_support/core_ext/hash/slice.rb'

def foo(*args)
  puts "ARGS: #{args}"
end

opts = {hash2: 'bar', hash3: 'baz'}
foo *opts.slice(:hash2, :hash3).values

...或者您可以修改自己的解决方案:

class Hash
  def pluck(*keys)
    keys.map {|k| self[k] }
  end
end

def foo(*args)
  puts "ARGS: #{args}"
end

opts = {hash2: 'bar', hash3: 'baz'}
foo *opts.pluck(:hash2, :hash3)

【讨论】:

    猜你喜欢
    • 2011-02-27
    • 2015-10-06
    • 2012-04-23
    • 1970-01-01
    • 2011-08-06
    • 2012-12-13
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多