是什么class << self在Ruby中做什么?
我错过了某个地方的备忘录,我希望你能解释一下这个.
为什么对象的本征类不同self.class?
class Foo
def initialize(symbol)
eigenclass = class << self
self
end
eigenclass.class_eval do
attr_accessor symbol
end
end
end
Run Code Online (Sandbox Code Playgroud)
我的逻辑系列等同于特征类,class.self非常简单:
class << self是一种声明类方法的方法,而不是实例方法.这是捷径def Foo.bar.
因此在对类对象的引用中,返回self应该相同self.class.这是因为,class << self将设置self以Foo.class用于类方法的定义/属性.
我只是困惑吗?或者,这是Ruby元编程的偷偷摸摸的伎俩吗?
类的本征类(或元类)中的类方法和方法只有两种方法来定义一个东西吗?
否则,有什么区别?
class X
# class method
def self.a
"a"
end
# eigenclass method
class << self
def b
"b"
end
end
end
Run Code Online (Sandbox Code Playgroud)
难道X.a和X.b不同的表现以任何方式?
我认识到我可以通过打开特征类来覆盖或别名类方法:
irb(main):031:0> class X; def self.a; "a"; end; end
=> nil
irb(main):032:0> class X; class << self; alias_method :b, :a; end; end
=> #<Class:X>
irb(main):033:0> X.a
=> "a"
irb(main):034:0> X.b
=> "a"
irb(main):035:0> class X; class << self; def a; "c"; end; end; end
=> nil
irb(main):036:0> X.a
=> "c"
Run Code Online (Sandbox Code Playgroud) 在Ruby中轻松获取所有模块的列表:
ObjectSpace.each_object(Module).to_a
Run Code Online (Sandbox Code Playgroud)
但是,是否可以获得所有特征类(也称为单例类或元类)的列表?或者本征类是不可见的?
我试过了
str = "foo"
my_metaclass = class << str; self; end
my_metaclass.class == Class # my_metaclass' class is Class
ObjectSpace.each_object(Class).include?(my_metaclass) # false
ObjectSpace.each_object.include?(my_metaclass) # still false
# Just to show each_object works
ObjectSpace.each_object(Class).include?(String) # true
Run Code Online (Sandbox Code Playgroud)
我正在尝试获取特征类,因为我想列出脚本中定义的所有方法.我可以查找模块和类定义的所有实例方法,然后查找模块和类(或者所有对象,如果我想要咀嚼CPU)的单例方法,但这似乎有点hackish.
我已经定义了Vehicle这样的模块
module Vehicle
class <<self
def build
end
private
def background
end
end
end
Run Code Online (Sandbox Code Playgroud)
致电Vehicle.singleton_methods退货[:build].
如何检查定义的所有私有单例方法Vehicle?
在Ruby中,获取类的本征类Foo是一个简单的
eigenclass = class << Foo; self; end
#=> #<Class:Foo>
eigenclass = Foo.singleton_class #2.1.0
#=> #<Class:Foo>
Run Code Online (Sandbox Code Playgroud)
我对逆操作感兴趣:从本征类本身获取本征类的所有者:
klass = eigenclass.owner
#=> Foo
Run Code Online (Sandbox Code Playgroud)
我不确定这是否可行,因为本征类是其匿名子类Class,因此Foo在其继承层次结构中无处可见.检查本征类的方法列表也不令人鼓舞.eigenclass.name回报nil.唯一让我希望这是可能的:
Class.new # normal anon class
#=> #<Class:0x007fbdc499a050>
Foo.singleton_class
#=> #<Class:Foo>
Run Code Online (Sandbox Code Playgroud)
显然,本征类的to_s方法知道关于所有者的一些事情,即使在实例化特征类时该信息是硬编码的.因此,我所知道的唯一方法Object.const_getting就是那样的hacky
Object.const_get eigenclass.to_s[/^#\<Class\:(?<owner>.+)\>$/, :owner]
#=> Foo
Run Code Online (Sandbox Code Playgroud) 我目前正在尝试使用Ruby和Rails,我在关于元编程的教程和书籍中有几个部分.许多人提到它是Ruby的重要组成部分,但它们并没有真正详细说明.这就好像元编程是Ruby程序员的最后边界.来自.NET背景我很难理解它为什么如此有用.
我理解常规方法查找路径即class, superclass/module, all the way up to BasicObject.我认为对于单链版本的链也是如此,但是当您在元链中混合模块时似乎并非如此.我很感激,如果有人能解释为什么在下面的示例中,当我将此模块包含在Vehicle的本征类中时,调用Automobile模块的banner方法而不是单例版本.
module Automobile
def banner
"I am a regular method of Automobile"
end
class << self
def banner
"I am a singleton method of Automobile"
end
end
end
class Vehicle
def banner
"I am an instance method of Vehicle"
end
class << self
include Automobile
def banner
puts "I am a singleton method of Vehicle"
super
end
end
end
class Car < Vehicle
def banner
"I am …Run Code Online (Sandbox Code Playgroud) 在Ruby中,该方法puts是Kernel模块的单例方法。
通常,当一个模块是另一个模块的included或extended时,该模块(而不是其单例类)将被添加到继承树中。这有效地使模块的实例方法可用于该模块或其单例类(分别用于include和extend)...但是混合模块的单例方法仍然不可访问,因为模块的单例类不是曾经添加到继承树中。
那为什么要使用puts(和其他内核单例方法)?
Kernel.singleton_methods(false)
# => [:caller_locations, :local_variables, :require, :require_relative, :autoload, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :test, :warn, :autoload?, :fork, :binding, :exit, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :URI, :eval, :iterator?, :block_given?, :catch, :throw, :loop, :gets, :sleep, :proc, :lambda, :trace_var, :untrace_var, :at_exit, :load, :Rational, :select, :Complex, :syscall, :open, :printf, :print, :putc, :puts, :readline, :readlines, :`, :p, :system, :spawn, :exec, :exit!, …Run Code Online (Sandbox Code Playgroud) 我试图将类的实例化限制为只有一个(不使用单例),但我不能.我尝试使用类变量(@@),但没有运气.我用Google搜索并发现了这个:
class A
@count = 0
class << self
attr_accessor :count
end
def initialize val
@a = val
self.class.count += 1
end
end
a=A.new 42
b=A.new 43
Run Code Online (Sandbox Code Playgroud)
我搜索了"类"自我 "的解释,希望找到一个更好的(或者只是一个更简单和干净),但是反过来,没有运气.最后,经过一些测试后我得出结论,'class << self '只是一个块包装器,你可以在其中定义类方法.那么,这是正确的吗?
问候!
eigenclass ×10
ruby ×10
class ×2
class-method ×1
inheritance ×1
metaclass ×1
mixins ×1
overriding ×1
reflection ×1
singleton ×1