Ruby:如何确定对象是否为单例

时间:2018-11-17 20:07:02

标签: ruby singleton

Object#singleton_class的Ruby文档文档:

  

返回 obj 的单例类。此方法创建一个新的   如果 obj 没有一个单例类。

因此,(尽管有一些注释)对象并非总是具有单例类。接下来,如果该对象具有单例类,则将其称为单例

新创建的对象没有单例类,因此不是单例:

a = "string"                     # => "string"          # not (yet) a singleton
b = String.new("another one")    # => "another one"     # not (yet) a singleton
[a.class, b.class]               # => [String, String]

仅在定义单例方法之后,对象才成为单例

def a.greet
  "hello"
end

或在创建单例类后,由于为对象的单例类定义了类变量

class << b
  @var = 42
end

不幸的是,在Ruby中,对 class 方法的调用不会显示该对象是否为单例,因为对于单例而言,该方法不会返回实际的(单例)类,而是用于创建以下对象的类对象:

[a.class, b.class]  # => [String, String]

如果对象实际上是单身人士,则仅调用 Marshal.dump 即可:

Marshal.dump(a, $stdout)
# TypeError: singleton can't be dumped

Marshal.dump(b, $stdout)
# TypeError: singleton can't be dumped

还有其他更优雅的方法来确定对象是否为单例吗?

1 个答案:

答案 0 :(得分:1)

经过一些额外的研究,我正在更新此答案。感谢Amadan对我的related question的深刻见解。

您可以采用两种单例方法来确定对象是否包含“大量”单例,以防止其被封送。

a = "string-a"
b = "string-b"
c = "string-c"

def a.greet
  "hello"
end

class << b
  @var = 42
end

def no_substantial_singleton?(obj)
  obj.singleton_class.instance_methods(false).empty? &&
  obj.singleton_class.instance_variables.empty?
end

def marshal_if_possible(obj)
    puts Marshal.dump(obj) if no_substantial_singleton?(obj)
end

marshal_if_possible(a) #=>
marshal_if_possible(b) #=>
marshal_if_possible(c) #=> 'string-c:ET'