我读到下面的代码片段实现了所谓的 partial class :
class A
def a
puts 'a'
end
end
class B < A
def ba1
puts 'ba1'
end
end
class A
def b
puts 'b'
end
end
class B < A
def ba2
puts 'ba2'
end
end
ob = B.new
ob.a
ob.b
ob.ba1
ob.ba2
从两个类B
扩展了两个类A
。我不明白红宝石如何知道A
B
的延伸范围。在创建B
的实例时,ruby如何知道它是B
?执行结果是:
a
b
ba1
ba2
初始化的B
是两个B
类的实例。有人可以解释一下吗?
答案 0 :(得分:7)
当您在Ruby中编写一个已经声明的类时,您不会覆盖该类,而是 patch 它。
这意味着ruby不会忘记旧的定义,而是添加它。
只有一个B
类 - 它是两个class B
块中的复合代码。
例如:
class A
def a
puts 'a'
end
end
a = A.new
a.public_methods(false)
# => [:a]
class A
def b
puts 'b'
end
end
a.public_methods(false)
# => [:a, :b]
在此示例中,在创建A
的实例之后,类a
已更改,但正如您所见,它知道添加了一个新方法(public_methods
列出了实例的可用方法。
有些事情你不能做,例如 - 改变一个类的父类。如果我们尝试采用上面的代码,并声明另一个块:
class A < String
def c
puts 'c'
end
end
# TypeError: superclass mismatch for class A
你得到一个错误,说你正在尝试更改基类,这是不可能的(如果在初始声明中没有继承声明,则该类隐式继承自Object
)
答案 1 :(得分:5)
唯一的B
类,继承自A
。诀窍是你可以在不同的地方自由声明B
(显然,这允许你 monkeypatch 现有的类。)
编写class B < A
后,如果尚未定义B
类,则会打开现有的B
进行扩展,或者正在创建新的{{1}}。
希望它有所帮助。
答案 2 :(得分:3)
没有&#34;部分课程&#34;在Ruby中。部分类是C#的一个特性,而不是Ruby。
在Ruby中,类定义表达式将在类的上下文中执行它内部的任何内容。你可以拥有任意数量的类声明表达式,但这并不重要。这允许您分段定义您的类,即使在不同的文件中,甚至在不同的库中也是如此。它还允许某人 else 稍后(重新)定义您的班级。
在Python中,这被称为&#34;猴子修补&#34;并且经常不赞成,Ruby社区已经采用了这个术语,但具有中性意义,因为,实际上,在Ruby中所有类定义都是猴子修补!
那么,你上面会有什么
A
已存在,则修改A
的课程定义,如果不存在,则修改新课程。B
已存在,则修改B
的班级定义,如果不存在则修改新班级。 (B
是否已经存在但是具有不同于A
的超类,这会引发TypeError "superclass mismatch"
。)A
的类定义(因为A
已定义)。B
的类定义(因为B
已经定义)。我们本可以省略超类,在这种情况下,我们会假设现有的超级类B
(即A
)。顺便说一下:从技术上讲,A
和B
不是课程。它们是引用到类的变量(更准确地说,常量)。类是对象,它们可以被变量引用,作为参数传递给方法,从方法等返回。
此外,超类声明不必是常量,它可以是任意Ruby表达式:
class Foo < if rand < 0.5 then String else Array end
end
完全有效(并且完全没用;-))
class Foo < Bar; end
def qux(sym); const_get(sym) end
class Foo < qux(:Bar); end
也是完全有效的,不会产生超类不匹配,因为常量Bar
和方法调用qux(:Bar)
都返回相同的对象(这是一个类)。
答案 3 :(得分:1)
可以重新定义Ruby类定义。第二个class A
只是向现有类添加了新方法。第二个class B < A
同样扩展了B
的定义。
答案 4 :(得分:1)
# In Ruby writing
class A
def a; puts 'a' end
end
class A
def b; puts 'b' end
end
# is same as writing
class A
def a; puts 'a' end
def b; puts 'b' end
end