Ruby中基于块参数动态创建方法实现DRY赋值的问题咨询
解决方案
你不需要使用define_method动态定义方法,Ruby原生支持动态调用实例方法,直接用public_send触发对应属性的setter方法即可,写法如下:
首先可以把需要赋值的属性列表提前定义在循环外部(避免每次循环重复生成数组):
# 提前定义需要同步的属性名,注意和hash、MySimpleObject的属性名保持一致 TARGET_ATTRIBUTES = %w[foo bar baz lorem ipsum]
然后修改遍历逻辑:
array_of_hashes.each_with_object(state) do |stats, memo| # 此处请根据你实际的state哈希的key规则,取出对应的MySimpleObject实例 current_state = memo[stats['key']] TARGET_ATTRIBUTES.each do |attr| # 动态调用setter方法,属性名加=就是对应的赋值方法名 current_state.public_send("#{attr}=", stats[attr].to_d) end end
补充说明
- 所有形如
state.foo = xxx的赋值,本质都是调用state.foo=(xxx)方法,public_send可以根据字符串/符号动态调用任意公开方法 - 如果
MySimpleObject的setter是私有方法,可以换成send调用,不过通常建议优先用public_send避免意外调用私有方法 - 如果你可以修改
MySimpleObject的实现,还可以新增一个批量赋值的方法进一步简化逻辑:
class MySimpleObject def assign_attributes(attrs) attrs.each do |k, v| public_send("#{k}=", v.to_d) if respond_to?("#{k}=") end end end # 调用时直接传hash对应字段即可 array_of_hashes.each_with_object(state) do |stats, memo| current_state = memo[stats['key']] current_state.assign_attributes(stats.slice(*TARGET_ATTRIBUTES)) end
内容的提问来源于stack exchange,提问作者dehelden
相关产品推荐
相关产品推荐

