下面的代码尝试创建一个MyClass类,它将方法self.add的调用委托给调用方法self.newAdd返回的对象。
class MyAdd
def add(a,b)
a + b
end
end
class MyClass
def self.newAdd
MyAdd.new
end
def self.delegate(*methods, options)
return unless options.has_key?(:to)
methods.each do |method|
define_method method, ->(*args, &prc) do
delegated_to = self.send(options[:to])
delegated_to.send(method, *args, &prc)
end
end
end
class << self
debugger;
delegate :add, to: :newAdd
end
end
运行此代码时发生的错误是
NoMethodError:#
的未定义方法'委托'<Class:MyClass>
如果我导航到保存文件的目录并打开解释器,则执行在第四行到最后一行的调试器处停止。然后,我可以查看自己和MyClass的可用方法
require_relative './test.rb'
MyClass.methods - Object.methods #[:newAdd, :delegate]
self.methods - Object.methods #[:nesting]
self # #<Class:MyClass>
self.class # Class
MyClass.class # Class
为什么self
与MyClass
范围内的class << self
不一样?更具体地说,为什么方法delegate
在class << self
内无法自我使用?
答案 0 :(得分:3)
为什么self与类中的MyClass不同?&lt;&lt;自我范围。
因为class关键字总是改变范围:
class MyClass
puts self #=> MyClass
class <<self
puts self #=>MyClass’s singleton class
end
end
更具体地说,为什么方法委托对自己不可用 在课堂内&lt;&lt;自?
class MyClass def self.delegate puts "executing MyClass.delegate()" end class <<self delegate end end --output:-- 1.rb:8:in `singleton class': undefined local variable or method `delegate' for #<Class:MyClass> (NameError) from 1.rb:7:in `<class:MyClass>' from 1.rb:1:in `<main>'
请注意,以下结构是等效的:
class MyClass
def self.delegate
puts "executing MyClass.delegate()"
end
end
MyClass.delegate
--output:--
executing MyClass.delegate()
和
class MyClass
class <<self
def delegate
puts "executing MyClass.delegate()"
end
end
end
MyClass.delegate
--output:--
executing MyClass.delegate()
因此,您的代码相当于:
class MyClass
class <<self
def delegate
puts "executing MyClass.delegate()"
end
delegate
end
end
如果你暂时忽略外部MyClass,那么你定义了一个这样的类:
class <<self
def delegate
puts "executing MyClass.delegate()"
end
delegate
end
可以像这样复制相同的结构:
class Dog
def bark
puts “woof”
end
bark
end
会产生相同类型的错误:
1.rb:7:in `<class:Dog>': undefined local variable or method `bark' for Dog:Class (NameError)
from 1.rb:1:in `<main>'
当你调用一个方法而你没有指定一个接收者时,ruby使用当前分配给自变量的任何对象作为接收者。
在方法中,ruby将调用方法的对象分配给自变量。调用方法的对象与定义方法的类(对象)不同。
在类中,但在任何方法定义之外,ruby会将类(对象)分配给self。
请注意,Dog类的实例可以调用Dog类中的def,例如:吠()。类似地,单例类的实例可以在单例类中调用def,例如, delegate() - 单例类本身不能在单例类中调用def。它们被称为单例类的全部原因是因为单例类只有一个实例 - 在您的情况下,单例类的一个实例是MyClass。因此,MyClass可以调用delegate(),但是单例类不能调用delegate()。
我真的不明白eignclass上的类方法是什么 但是。
就个人而言,我不使用eigenclass
这个词。在我看来,ruby已经决定该术语是singleton class
。如果查看Object类的文档,则其中没有包含eigenclass
的方法名称,但其中包含singleton class
的方法名称。
所有对象都有一个单例类。单例类是一个对象。因此,每个单例类也都有一个单例类 - 这意味着单例类的链是无限的:
class Dog
end
s1 = Dog.singleton_class
puts s1
s2 = s1.singleton_class
puts s2
s3 = s2.singleton_class
puts s3
--output:--
#<Class:Dog>
#<Class:#<Class:Dog>>
#<Class:#<Class:#<Class:Dog>>>
这意味着你可以做这样的事情:
class Dog
class <<self #s1
class <<self #s2
def greet #Instances of s2 can call greet, and the only instance of s2 is s1.
puts "hello"
end
end
end
end
class Dog
class <<self
#Inside here self = Dog's singleton class = s1
greet #equivalent to Dogs_singleton_class.greet
end
end
--output:--
hello
但是,我从未见过有人在代码中使用单例类(s2)的单例类。很久很久以前我曾经做过一次回答问题,没有人知道我在说什么。
有一些方法查找图here,这可能证明是有用的。
答案 1 :(得分:1)
以下是代码的重新设计部分,无误地运行:
class MyClass
def self.newAdd
MyAdd.new
end
def self.delegate(*methods, options)
return unless options.has_key?(:to)
methods.each do |method|
target = self
define_method method, ->(*args, &prc) do
delegated_to = target.send(options[:to])
delegated_to.send(method, *args, &prc)
end
end
end
delegate :add, to: :newAdd
end
作为一个注释,请尝试指出像new_add
这样的命名方法,并避免在其中使用大写字母。
您无法使用const_get
来检索方法。您正在寻找的是method
,但这并非总是最好的计划。 send
通常就足够了。
答案 2 :(得分:0)
我发布的实际可行的代码版本如下:
class MyAdd
def add(a,b)
a + b
end
end
module Delegate
def delegate(*methods, options)
return unless options.has_key?(:to)
# methods are the methods that should be delegated to
# the object returned by calling the method passed in options[:to]
methods.each do |method|
define_method method, ->(*args, &prc) do
delegated_to = self.send(options[:to])
delegated_to.send(method, *args, &prc)
end
end
end
end
class MyClass
extend Delegate
def self.newAdd
MyAdd.new
end
class << self
extend Delegate
delegate :add, to: :newAdd
end
end
现在,如果我们从delegate :add, to: :newAdd
内拨打class << self
,我们会将类方法add
的调用委托给类方法newAdd
。这样做的原因是在class << self
内部,self
是类MyClass
,我们所在的范围self
是MyClass
的单例类。通过在这里扩展模块Delegate
,我们在这个单例类上定义了一个类方法。该方法称为委托,并在其中调用define_method,它在单例类(例如,add
)上创建实例方法,因此它们是原始类(MyClass
)上的类方法。
如果我们从类MyClass语句中调用delegate,我们会将实例方法add
的调用委托给实例方法newAdd
(如果存在)。原因是在class MyClass
创建的范围内,self是MyClass,通过在此处扩展模块Delegate,我们创建了一个类方法delegate
(MyClass上的实例方法delegate
& #39; s单身类)。这个类方法调用define_method,它在MyClass上创建实例方法(例如,添加)。
我们最终得到了两个名为delegate的方法,一个是MyClass的类方法,另一个是MyClass的单例类的类方法。