如何让Ruby定义Hash时遇到重复键直接抛出异常而非警告
Ruby 2.7 实现Hash定义时重复键抛出异常的方案
Ruby原生Hash字面量语法默认仅对重复键输出警告,没有内置开关直接将该警告转换为异常,可通过以下两种方案实现需求:
方案1:全局修改警告处理逻辑,将重复键警告转为异常
通过重写Warning模块的warn方法,匹配到Hash重复键警告时直接抛出异常,代码如下:
Warning.module_eval do alias_method :original_warn, :warn def warn(msg, **kwargs) if msg.include?("key is duplicated and overwritten") raise ArgumentError, msg.chomp end original_warn(msg, **kwargs) end end
添加上述配置后,运行{a: 1, b: 2, a: 3}会直接抛出异常,而非仅输出警告:
ArgumentError (warning: key :a is duplicated and overwritten on line 1)
该方案全局生效,所有Hash重复键的场景都会触发异常,如果仅需要局部校验可使用方案2
方案2:封装自定义Hash构造方法,局部校验重复键
封装专用的Hash构造方法,显式检查是否存在重复键,不会影响全局逻辑:
# 适用Symbol键场景 def strict_hash(**kwargs) if kwargs.keys.size != kwargs.keys.uniq.size duplicate_key = kwargs.keys.tally.find { _2 > 1 }[0] raise ArgumentError, "duplicate key: #{duplicate_key.inspect}" end kwargs end
使用时替换原有Hash字面量写法即可:
# 正常构造 h = strict_hash(a: 1, b: 2) # 重复键时抛出异常 h = strict_hash(a: 1, b: 2, a: 3) # 抛出ArgumentError: duplicate key: :a
如果需要兼容字符串、数值等其他类型的键,可以调整为接收键值对数组的形式:
def strict_hash(*pairs) h = {} pairs.each do |k, v| raise ArgumentError, "duplicate key: #{k.inspect}" if h.key?(k) h[k] = v end h end # 使用示例 h = strict_hash([:a, 1], ["b", 2], [1, 3])
内容的提问来源于stack exchange,提问作者Niels Kristian
相关产品推荐
相关产品推荐

