Ruby 2.7.0+中以Hash传递双splat参数触发ArgumentError问题
Ruby 3.x中
**opts无法接收Hash字面量传参的问题解析 问题复现
定义接收位置参数和关键字参数的方法:
def test(arg, **opts) puts arg, opts end
- 直接传递关键字参数时正常运行:
test(:foo, from: true, to: false) # 输出: :foo 和 {:from=>true, :to=>false} - 传递Hash字面量时触发参数错误:
test(:foo, { from: true, to: false }) # 报错:(irb):1:in `test': wrong number of arguments (given 2, expected 1) (ArgumentError)
核心原因
Ruby 2.7版本开始明确了关键字参数与普通Hash的边界,彻底取消了二者之间的自动转换:
**opts是专门用于接收关键字参数的形参,它只会捕获调用时以key: value形式传递的关键字参数- 当你传入
{ from: true, to: false }时,这是一个独立的Hash对象,会被识别为第二个位置参数,但方法仅定义了一个位置参数arg,因此Ruby判定参数数量不匹配,抛出错误
解决方案
如果需要让方法同时支持两种传参方式,可选择以下任一方案:
方案1:调用时显式展开Hash
在Hash前添加**操作符,将其转换为关键字参数:
test(:foo, **{ from: true, to: false }) # 正常执行,效果与直接传关键字参数一致
方案2:修改方法定义兼容Hash参数
同时声明一个可选Hash参数和关键字参数,Ruby会自动合并两者的内容:
def test(arg, opts = {}, **kwargs) combined_opts = opts.merge(kwargs) puts arg, combined_opts end # 两种调用方式都正常运行 test(:foo, { from: true, to: false }) test(:foo, from: true, to: false)
内容的提问来源于stack exchange,提问作者Tony Beninate
相关产品推荐
相关产品推荐

