我有一个简单的模块,它定义了一个常量并将其设为私有(private):
module Foo
Bar = "Bar"
private_constant :Bar
end
我可以将它包含在这样的类中,并且它按预期工作:
class User
include Foo
def self.test
Bar
end
end
puts User.test
# => Bar
begin
User::Bar
rescue => exception
puts "#{exception} as expected"
# => private constant Foo::Bar referenced as expected
end
(我们称之为“典型类”定义)
然后我尝试了 Class.new
方法,但失败得很惨:
X = Class.new do
include Foo
def self.test
Bar # Line 28 pointed in the stack trace
end
end
begin
X::Bar
rescue => exception
puts "#{exception}"
# => private constant Foo::Bar
end
puts X.test
# test.rb:28:in `test': uninitialized constant Bar (NameError)
# from test.rb:28:in `<main>'
为什么?我一直认为 class Something
和 Something = Class.new
是等价的。实际区别是什么?
然后我灵机一动,想起了定义类方法的替代方法,它确实有效:
X = Class.new do
class << self
include Foo
def test
Bar
end
end
end
begin
X::Bar
rescue => exception
puts "#{exception}"
# => uninitialized constant X::Bar
end
puts X.test
# Bar
同样 - 为什么这个有效,为什么异常现在不同了:private constant Foo::Bar
vs uninitialized constant X::Bar
?
这 3 种初始化类的方式似乎有细微差别。
- 完全符合我的要求:Bar 可在内部访问,访问它会给出引用私有(private)常量的异常。
- 第二个给出“ok”异常,但无权访问 Bar 本身
- 第三个可以访问,但现在给出略有不同的异常
这里到底发生了什么?
最佳答案
这是 Ruby 中最大的陷阱之一:常量定义范围是部分句法,也就是说,它取决于围绕它的代码的结构。
module Foo
Bar = "Bar"
end
Bar
在module
里面定义,因此它在该模块中定义。
class << self
include Foo
end
Bar
包含在 class
中定义,所以它在那个类中定义。
Class.new do
include Foo
end
没有封闭class
或 module
(这是一个带有 block 的普通方法调用),所以常量是在顶层定义的。
至于你的第三个错误,我认为这是因为常量是在单例类中定义的(这就是 class << self
是什么)而不是类本身。它们是两个独立的类对象。
关于ruby - 定义类的不同方式如何影响包含作品的方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71221055/