gpt4 book ai didi

ruby - 为什么模块调用的 block 不能通过在 Ruby 中实现类来修改对象?

转载 作者:数据小太阳 更新时间:2023-10-29 08:37:18 27 4
gpt4 key购买 nike

我有一些数据保存在深度嵌套的哈希和数组中,但我在数据的文本编码方面遇到了麻烦。我确实知道文本是用“UTF-8”编码的,所以我决定遍历每个元素并强制编码。

因此,我为 Enumerable 模块创建了一个名为 deep_each 的方法:

module Enumerable
def deep_each(&block)
self.each do |element|
if element.is_a? Enumerable then
element.deep_each(&block)
else
block[element]
end
end
end
end

并且期望能够使用以下方法调用来修复数据:

deephash.deep_each {|element| element.force_encoding("UTF-8") if element.class == String}

但结果却令人失望:

deephash.deep_each {|element| element.force_encoding("UTF-8") if element.class == String}

> RuntimeError: can't modify frozen String
> from (pry):16:in `force_encoding'

然后我将函数向下移动到层次结构中的“Array”和“Hash”类:

class Hash
def deep_each(&block)
self.each do |element|
if [Array, Hash].include? element.class then
element.deep_each(&block)
else
block[element]
end
end
end
end

class Array
def deep_each(&block)
self.each do |element|
if [Array, Hash].include? element.class then
element.deep_each(&block)
else
block[element]
end
end
end
end

令人惊讶的是,同样的调用现在有效了。

我在这里违反了什么约束,我如何为所有 Enumerables 定义一个方法而不为每个 Enumerables 定义它?

最佳答案

据我所知,您的 Enumerable 版本和 Array/Hash 猴子补丁应该会遇到完全相同的错误。我愿意。您确定在这两种情况下都使用相同的 deephash 吗?

通常,当您在散列上循环 each 时,您会将键和值都传递给 block 。您将单个值 element 传递给 block 。这是一个包含键和值的数组:

irb> {a:1, b:2}.each {|el| puts el.inspect }
[:a, 1]
[:b, 2]

您的 deep_each 检查这是否是一个 Enumerable,它是,所以它调用列表中的 deep_each。然后,最后,您到达叶子并调用键和值上的 block 。该 block 检查它是否正在使用字符串,如果是,则强制编码。

如果您的哈希键是一个字符串,您将尝试对其进行变异。但是哈希键被卡住,因此引发了 RuntimeError: can't modify frozen String

irb> {a: {b: {c: "abc"}}}.deep_each { |el| el << "efg" if String === el}
=> {:a=>{:b=>{:c=>{:d=>"abcefg"}}}}
irb> {a: {b: {"c" => "abc"}}}.deep_each { |el| el << "efg" if String === el}
RuntimeError: can't modify frozen String

关于ruby - 为什么模块调用的 block 不能通过在 Ruby 中实现类来修改对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28920104/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com