这是 attr_reader 应该与数组一起使用的方式吗?
class User
def initialize
@interests = []
end
attr_reader :interests
end
u = User.new
=> #User:0x1d2cb60
u.interests << "music"
=> ["music"]
u.interests[1] = "travelling"
=> ["travelling"]
u.interests = nil
NoMethodError: undefined method `interests=' for u:User
我只是检查我自己的解释是否正确,如果没有,请纠正我:
attr_reader是不是阻止我分配“@interests”值,因为你没有直接修改实例变量本身(它仍然保存对数组对象的引用),但你只是在操作数组对象引用的值?
如果这是正确的,是否有一种快速而好的方法可以避免attr_reader让我对数组值进行写访问,但让我阅读它们?
由于
答案 0 :(得分:2)
关于“不直接修改实例变量”,您所描述的内容是正确的。 @interests没有变化,但是因为它是一个可变对象,所以来电者可以潜入你身后。
如果您想禁止编辑:interests字段,只需freeze
即可。时间很棘手,因为你想在将对象交还给用户之前阻止写入,所以你可能需要在对象创建时这样做:
def initialize(whatever)
@foo = bar
@interests = %w(a b c).freeze
end
如果您的对象想要更改@interests,请小心。您需要完全重建阵列,因为您无法解冻对象。
答案 1 :(得分:1)
编写您自己的getter,并使用dup提供原始数组的副本:
def interests
@interests.dup
end
完整代码:
class User
def initialize
@interests = []
end
def interests
@interests.dup #
end
end
# Without dup:
u.interests # => []
u.interests << "music"
u.interests # => ["music"]
# With dup:
u.interests # => []
u.interests << "music"
u.interests # => []
(当然,对于多维数组和类似的分层数据结构,您需要稍微更先进的解决方案)