【发布时间】:2012-01-14 05:53:21
【问题描述】:
ruby 中是否有一个钩子,每次某个变量的值发生变化时都会调用它?
【问题讨论】:
-
没有。但是你可以使用访问器。
ruby 中是否有一个钩子,每次某个变量的值发生变化时都会调用它?
【问题讨论】:
如果您为 Ruby 编写 C 扩展,您实际上可以创建一个全局变量,当有人设置它时触发一个 setter 钩子。
但您可能不想这样做,因为您必须编写一些 C 语言,并且管理它可能会很痛苦。
更好的策略是通过适当的方法读取和设置变量。然后,当调用 setter 方法时,您可以做任何您想做的事情。这是一个将变量封装在对象内的示例:
class Foo
def bar=(v)
@bar = v
# do some stuff
end
def bar
@bar
end
end
同样,您可以将变量封装在模块或类中,而不是对象中。
【讨论】:
rb_define_hooked_variable
序言:我这不是一个解决方案(pst 已经写过:没有),但也许它可以在特殊情况下提供帮助。
我的第一个想法是使用freeze 来获得解决方案:
a = "aa"
a.freeze
a << 'b' #can't modify frozen string (RuntimeError)
现在我们必须重新定义freeze,当变量改变值时我们会得到一个提示:
module FreezeWarning
def freeze
puts "#{self}: I am changed"
end
end
a = "aa"
a.extend(FreezeWarning)
a.freeze
a << 'b' #aa: I am changed
第一个问题:There is no way to get the variable name。
你可以用一个额外的变量来解决这个问题(你可以定义你自己的变量标识,它不能是名字)
module FreezeWarning
def change_warning(name)
@varname = name
self.freeze
end
def freeze
puts "<#{@varname}> (#{self}): I am changed"
end
end
a = "aa"
a.extend(FreezeWarning)
a.change_warning('a')
a << 'b' #<a> (aa): I am changed
但更大的问题:这只适用于值的变化,不适用于新的分配:
a = 5
a.freeze
a = 4
p a # -> 4
所以这只是一个非常有限的“解决方案”。
【讨论】: