在 Ruby 3 中模式匹配哈希时的默认值

Default values when pattern matching a hash in Ruby 3

提问人:Alexey Romanov 提问时间:3/26/2023 更新时间:3/27/2023 访问量:185

问:

在 Ruby 3 中,

hash => {a:}

工作方式类似于 JS

{ a } = hash

除了如果不是键,它会抛出异常,而不是分配 .好的,我们可以做:ahasha = nil

hash => {a:} rescue nil

除非如果存在某些键而缺少其他键,则会产生不希望的结果:

{a: 1, b: 2} => {b:, c:} rescue nil
puts "b: #{b}, c: #{c}"

显示 和 都是 而不是 期望的 .有没有一种简单的方法可以得到这个结果?或者更一般地说,使用非默认值模拟 JS 哈希解构?bcnilb = 2, c = nilnil

红宝石 Ruby-3

评论


答:

0赞 Alexey Romanov 3/26/2023 #1

在写这个问题时,我想到了这个解决方法:

{a: some_default, **hash} => {a:}

或第二种情况

{b: nil, c: nil, **hash} => {b:, c:}

我不喜欢它,因为它复制了密钥并做了一些工作来创建左侧哈希,所以希望有人有更好的选择。

1赞 Alex 3/27/2023 #2

您可以通过创建一个响应以下对象来解决缺少键错误:deconstruct_keys

hash = {a: 1}

H(hash) => x:,y:,a:
x  # => nil
y  # => nil
a  # => 1

H(hash, "default") => x:,y:,a:
x  # => "default"
y  # => "default"
a  # => 1

H(hash, x: :z) => x:,y:,a:
x  # => :z
y  # => nil
a  # => 1

H(hash, "default", x: :z) => x:,y:,a:
x  # => :z
y  # => "default"
a  # => 1

deconstruct_keys当使用哈希模式时调用,这些键作为参数传递:=> x:,y:,a:

# DelegateClass to make H be like a hash, but pattern match differently.
# (it works just fine without DelegateClass)
#
#   H.new({a: 1}) # => {:a=>1}
#
class H < DelegateClass(Hash) 
  def initialize(hash, default = nil, **defaults)
    # since hash needs to be duped anyway
    @hash = defaults.merge hash               # defaults for specific key
    @default = default                        # default for any missing keys
    super(@hash)                              # get delegation going
  end

  def deconstruct_keys keys
    missing = keys - @hash.keys               # find what's missing
    missing.each { |k| @hash[k] = @default }  # add it to hash with default value
    @hash                                     # return for pattern matching
  end
end

# H() method, like a Hash() method.
def H(...) 
  H.new(...)
end

https://docs.ruby-lang.org/en/3.2/syntax/pattern_matching_rdoc.html#label-Matching+non-primitive+objects-3A+deconstruct+and+deconstruct_keys