【问题标题】:Ruby: execute singleton method in different contextRuby:在不同的上下文中执行单例方法
【发布时间】:2015-02-18 14:55:00
【问题描述】:

(经过编辑使问题更具体)

我想知道是否可以在另一个对象的上下文中执行单例方法,如下例所示:

class A
  def initialize
    @foo = 'foo'
  end
end

def A.singleton(*args)
  puts 'in singleton'
  puts @foo
end

A.new.instance_eval &A.method(:singleton)

# output is:
# - in singleton

# desired output:
# - in singleton
# - foo

【问题讨论】:

  • 你能证明你为什么要使用这种令人困惑的结构吗?我想不出为什么在模块上定义单例方法会导致在封闭模块中定义实例方法。如果我们知道用例,我们可能会向您展示一种更惯用的方法。
  • 这是一个实验,纯粹的句法实验,作为对某些方法进行分组或添加额外功能的一种方式。我很欣赏一种更惯用的方法可能是使用诸如special_method :baz 之类的类方法,但我只是在探索另一种方法。一个可能的应用程序可能是以这种方式记忆一个方法,即def memoize.baz,但我同意这很混乱,可能不是我在实际项目中使用的东西。不过,我仍然想知道这是否可能。

标签: ruby metaprogramming singleton-methods


【解决方案1】:

这是不可能的。事实上,当你尝试这样做时,Ruby 有一个特定的错误:

module Foo
  def self.bar
  end
end

class Baz
end

Foo.method(:bar).unbind.bind(Baz.new)
# TypeError: singleton method called for a different object

这确实是一个人为的限制,因为UnboundMethod#bind 可以很容易地跳过类型检查并让你去做。但是,如果您可以使用不同的接收器调用单例方法,那将是一个根本的矛盾:为 single 实例定义了单例方法。这是有道理的,这是不允许的。

【讨论】:

    【解决方案2】:

    我认为这是不可能的。具有讽刺意味的是,A::Singletons 本身就是一个单例(在单例模式的意义上),因此,因为系统中只有一个 A::Singletons,但 A 在许多不同的模块中可能是 includeded ,无法知道在哪个模块中添加该方法。

    【讨论】:

    • 谢谢约尔格。或许那是不可能的。虽然我确实更接近(我认为) - 我已经更新了这个例子。 instance_exec 方法确实调用了 baz 方法(用 puts 语句测试)但它没有打印 @bar 的值
    • 可以使用匿名模块代替A::Singletons 解决此问题,但即便如此,您也会遇到我的回答中提到的错误。
    猜你喜欢
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-10-04
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    相关资源
    最近更新 更多