2

这是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 给我对数组值的写访问权限,但让我读取它们?

谢谢

4

2 回答 2

2

关于“不直接修改实例变量”,您所描述的内容是正确的。@interests 没有改变,但是由于它是一个可变对象,调用者可以偷偷溜到你身后。

如果你想禁止编辑 :interests 字段,就freeze这样吧。时机很棘手,因为您想在将对象交还给用户之前阻止写入,因此您可能需要在对象创建时执行此操作:

def initialize(whatever)
   @foo = bar
   @interests = %w(a b c).freeze
end

如果您的对象想要对@interests 进行更改,请小心。您需要完全重建数组,因为您无法解冻对象。

于 2013-03-01T03:09:09.350 回答
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 # => []

(当然,对于多维数组和类似的分层数据结构,您需要更高级的解决方案)

于 2017-06-28T03:19:26.277 回答