【问题标题】:Hook to be called when a variable changes变量改变时调用的钩子
【发布时间】:2012-01-14 05:53:21
【问题描述】:

ruby 中是否有一个钩子,每次某个变量的值发生变化时都会调用它?

【问题讨论】:

  • 没有。但是你可以使用访问器。

标签: ruby variables


【解决方案1】:

如果您为 Ruby 编写 C 扩展,您实际上可以创建一个全局变量,当有人设置它时触发一个 setter 钩子。

但您可能不想这样做,因为您必须编写一些 C 语言,并且管理它可能会很痛苦。

更好的策略是通过适当的方法读取和设置变量。然后,当调用 setter 方法时,您可以做任何您想做的事情。这是一个将变量封装在对象内的示例:

class Foo
  def bar=(v)
    @bar = v
    # do some stuff
  end

  def bar
    @bar
  end
end

同样,您可以将变量封装在模块或类中,而不是对象中。

【讨论】:

【解决方案2】:

序言:我这不是一个解决方案(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

所以这只是一个非常有限的“解决方案”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    相关资源
    最近更新 更多