Ruby: 如何判断一个对象是否是单例

Ruby: how to find out if an object is a singleton

Object#singleton_class 的 Ruby 文档:

Returns the singleton class of obj. This method creates a new singleton class if obj does not have one.

因此,(尽管有一些评论)一个对象 并不总是 有一个单例 class。在下文中,如果这个对象有一个单例 class.

,我将对象 称为单例

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

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 变量被定义为对象的单例 class 而创建单例 class 之后

class << b
  @var = 42
end

不幸的是,在 Ruby 中 class 方法的调用不会显示对象是否是单例,因为对于单例,该方法不会 return 实际(单例)class 但 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

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

经过一些额外的研究,我正在更新这个答案。感谢 Amadan for his insightful answer to my .

您可以使用两种单例方法来确定一个对象是否包含 "substantial" 单例以防止其被编组。

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'