Ruby class 常量与继承之谜
Ruby class constants and inheritance mystery
为什么以下两个代码片段不会产生相同的输出? push
和 |=
之间的区别是一个棘手的区别。我想 |=
作为一项任务可能会有所作为?最重要的是,常量实际上不会在以后发生变化,我想不是吗?
代码来自this question. You can see it in action here的答案。
class LibraryItem
ATTRIBUTES = ['title', 'authors', 'location']
end
class LibraryBook < LibraryItem
ATTRIBUTES.push('ISBN', 'pages']
end
puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES
> ["title", "authors", "location", "ISBN", "pages"]
> ["title", "authors", "location", "ISBN", "pages"]
和
class Foo
ATTRIBUTES = ['title','authors','location']
end
class Bar < Foo
ATTRIBUTES |= ['ISBN', 'pages']
end
puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES
> ["title", "authors", "location"]
> ["title", "authors", "location", "ISBN", "pages"]
在第一个示例中,ATTRIBUTES
引用同一个数组,而您正在修改它。因此,
puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES
产生相同的结果。
而在第二种情况下,您正在做 a |= b
,这是 shorthand for a = a | b
。这将为 class Bar
创建一个名为 ATTRIBUTES
的新数组。因此,
puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES
产生不同的结果。
您可以在这个问题中阅读有关 Ruby 赋值运算符 的更多信息。 Ruby |= assignment operator
编辑
Ruby 数组使用 &
、|
运算符实现集合操作的小型集合。
单管道,|
执行联合操作,即仅添加唯一元素。
a = [:foo, :bar, :baz]
a |= [:baz, :buz] # => [:foo, :bar, :baz, :buz]
ruby 中的常量有点用词不当。重新分配常量会产生警告:
Foo=1
Foo=2
(irb):5: warning: already initialized constant Foo
但是没有什么能阻止您改变实际值本身,push
确实如此。如果你想防止这种情况发生,那么你可以冻结数组,即
class LibraryItem
ATTRIBUTES = ['title', 'authors', 'location'].freeze
end
改变数组的尝试现在会引发异常。虽然只有数组被冻结,所以你可以做类似
的事情
LibraryItem::ATTRIBUTES.first.upcase!
(假设您没有打开冻结的字符串文字)并且允许更改。除了单独冻结字符串(或在 ruby 2.3 及更高版本上为该文件打开冻结字符串文字)
之外,我不知道有什么解决方法
为什么以下两个代码片段不会产生相同的输出? push
和 |=
之间的区别是一个棘手的区别。我想 |=
作为一项任务可能会有所作为?最重要的是,常量实际上不会在以后发生变化,我想不是吗?
代码来自this question. You can see it in action here的答案。
class LibraryItem
ATTRIBUTES = ['title', 'authors', 'location']
end
class LibraryBook < LibraryItem
ATTRIBUTES.push('ISBN', 'pages']
end
puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES
> ["title", "authors", "location", "ISBN", "pages"]
> ["title", "authors", "location", "ISBN", "pages"]
和
class Foo
ATTRIBUTES = ['title','authors','location']
end
class Bar < Foo
ATTRIBUTES |= ['ISBN', 'pages']
end
puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES
> ["title", "authors", "location"]
> ["title", "authors", "location", "ISBN", "pages"]
在第一个示例中,ATTRIBUTES
引用同一个数组,而您正在修改它。因此,
puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES
产生相同的结果。
而在第二种情况下,您正在做 a |= b
,这是 shorthand for a = a | b
。这将为 class Bar
创建一个名为 ATTRIBUTES
的新数组。因此,
puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES
产生不同的结果。
您可以在这个问题中阅读有关 Ruby 赋值运算符 的更多信息。 Ruby |= assignment operator
编辑
Ruby 数组使用 &
、|
运算符实现集合操作的小型集合。
单管道,|
执行联合操作,即仅添加唯一元素。
a = [:foo, :bar, :baz]
a |= [:baz, :buz] # => [:foo, :bar, :baz, :buz]
ruby 中的常量有点用词不当。重新分配常量会产生警告:
Foo=1
Foo=2
(irb):5: warning: already initialized constant Foo
但是没有什么能阻止您改变实际值本身,push
确实如此。如果你想防止这种情况发生,那么你可以冻结数组,即
class LibraryItem
ATTRIBUTES = ['title', 'authors', 'location'].freeze
end
改变数组的尝试现在会引发异常。虽然只有数组被冻结,所以你可以做类似
的事情LibraryItem::ATTRIBUTES.first.upcase!
(假设您没有打开冻结的字符串文字)并且允许更改。除了单独冻结字符串(或在 ruby 2.3 及更高版本上为该文件打开冻结字符串文字)
之外,我不知道有什么解决方法