class Event
@event_list = {}
attr_reader :name, :value
def initialize(name, value)
@name = name
@value = value
end
def to_s
"#{@value}"
end
class << self
def event_list
@event_list
end
def event_list=(value); end
def register_event(name, value)
@event_list[name] = Event.new(name, value)
end
def registered_events
event_list
end
end
end
在上面的代码片段中,我可以使用Event.event_list访问@event_list,有趣的是我能够从外部修改此变量
Event.event_list[:name] = "hello"
Event.event_list # => { :name => 'hello' }
我怎样才能避免这种情况?我不想从外面修改@event_list。
答案 0 :(得分:1)
据我所知,您无法阻止外部代码修改Ruby中的实例变量。即使您不使用attr_reader
和attr_writer
,仍然可以使用Object#instance_variable_set
访问它。 Ruby没有私有变量(或常量),只有礼貌要求你不要修改的变量。
如果您没有定义event_list=
,那么这被视为@event_list
是私有变量的指示。这是解决您问题的方法。
然后是可变对象的问题。因为Ruby中几乎所有对象都是可变的,所以通常只要你能获得对象的引用,就可以改变它。
这可以通过Object#freeze
解决,它可以阻止对象被修改。不幸的是,这意味着即使你可以修改它。
Ruby对于锁定事物并不是很好。这种开放性是您可能需要学习使用的语言的核心部分。
答案 1 :(得分:1)
正如其他人所说,只需将方法设为私有:
class Event
@event_list = {a: 'dog'}
class << self
def pub_event_list
@event_list
end
def pub_event_list=(other)
@event_list=other
end
private
def event_list
@event_list
end
def event_list=(value)
@event_list = value
end
end
end
Event.event_list
#=> NoMethodError: private method `event_list' called for Event:Class
Event.pub_event_list
#=> {:a=>"dog"}
Event.event_list= {b: 'cat'}
#=> #NoMethodError: private method `event_list=' called for Event:Class
Event.pub_event_list= {b: 'cat'}
#=> {:b=>"cat"}
答案 2 :(得分:0)
您在单身人士上定义def event_list
,提供对变量的访问权限。将该方法设为私有
编辑:
当您声明@event_list
时,它在您的单例方法中具有范围。
class Event
@event_list = {}
class << self
def event_list
# scoped from above
@event_list
end
end
end
Event.event_list #=> {}
要删除访问权限,只需将方法设为私有:
class Event
@event_list = {}
class << self
private
def event_list
# scoped from above
@event_list
end
end
end
Event.event_list #=> NoMethodError: private method `event_list' called for Event:Class
答案 3 :(得分:0)
以下是我现在所做的事情,我不知道这是不是一个好的解决方案
class Event
@event_list = {}
attr_reader :name, :value
def initialize(name, value)
@name = name
@value = value
end
def to_s
"#{@value}"
end
class << self
def register_event(name, value)
@event_list = @event_list.merge(name => Event.new(name, value))
end
def registered_events
@event_list.freeze
end
end
end
现在我可以访问@event_list而不让其他人修改。