如何覆盖模块中的类常量和方法?
Posted
技术标签:
【中文标题】如何覆盖模块中的类常量和方法?【英文标题】:How to override class constants and methods from a module? 【发布时间】:2022-01-24 03:31:33 【问题描述】:我正在尝试创建一个模块来为某些类定义一些方法和常量。
这意味着可以在模块和包含该模块的类中定义相同的方法或常量。
在那种情况下,我想要控制(最好是在模块定义中,或者可能来自调用者,而不更改类代码)哪个优先。
通常,我希望使用模块中定义的方法或常量。
但是,除非我从类中删除它们,否则类中定义的那些似乎总是被使用。
module A
def self.included(clazz)
const_set(:CONST, clazz.name == "B" ? "constant from module A for B" : "constant from module A for C")
define_method(:a) do
"from module A"
end
end
end
class B
include A
CONST = "constant from class B"
def a
"from class B"
end
end
class C < B
include A
CONST = "constant from class C"
def a
"from class C"
end
end
b = B.new
c = C.new
p b.a, c.a
p B::CONST, C::CONST
在this REPL 打印上运行它
main.rb:3: warning: already initialized constant A::CONST
main.rb:3: warning: previous definition of CONST was here
"from class B"
"from class C"
"constant from class B"
"constant from class C"
有什么办法可以输出这个
"from class A"
"from class A"
"constant from module A for B"
"constant from module A for C"
不从 B 类或 C 类中删除常量 CONST
或方法 a
?
【问题讨论】:
【参考方案1】:首先,Ruby从上到下逐行解释代码,所以在你的例子中,Ruby在定义CONST =
之前读取module A
,结果,在类B或C中定义的CONST
将始终输出。
-> 将include A
移动到CONST=
下方
其次,在def self.included(clazz)
内部,self 是module A
而不是B 类或C 类,因此const_set
方法由module A
本身调用,因此没有B::CONST
或C::CONST
在这里定义。
-> 在def self.included(clazz)
中使用clazz.const_set
试试这个
module A
def self.included(base)
base.send :remove_const, :CONST if base.const_defined?(:CONST)
base.const_set(:CONST, base.name == "B" ? "constant from module A for B" : "constant from module A for C")
end
end
class B
CONST = "constant from class B"
include A
end
【讨论】:
以上是关于如何覆盖模块中的类常量和方法?的主要内容,如果未能解决你的问题,请参考以下文章