Ruby类常量与继承之谜

Ruby类常量与继承之谜,ruby,class,constants,immutability,Ruby,Class,Constants,Immutability,为什么以下两个代码段不产生相同的输出?push和|=之间的区别是一个棘手的问题。我想|=作为一项任务可能会有所不同?除此之外,常数在以后的变化中实际上是安全的,我想不是吗 代码来自对的回答。你可以看到 类库项目 属性=['title','authors','location'] 终止 类LibraryBook[“标题”、“作者”、“位置”、“ISBN”、“页面”] >[“标题”、“作者”、“位置”、“ISBN”、“页面”] 及 class Foo ATTRIBUTES = ['title

为什么以下两个代码段不产生相同的输出?
push
|=
之间的区别是一个棘手的问题。我想
|=
作为一项任务可能会有所不同?除此之外,常数在以后的变化中实际上是安全的,我想不是吗

代码来自对的回答。你可以看到

类库项目
属性=['title','authors','location']
终止
类LibraryBook[“标题”、“作者”、“位置”、“ISBN”、“页面”]
>[“标题”、“作者”、“位置”、“ISBN”、“页面”]

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"]
class-Foo
属性=['title','authors','location']
终止
类Bar[“标题”、“作者”、“位置”]
>[“标题”、“作者”、“位置”、“ISBN”、“页面”]

在第一个示例中,
属性
引用同一数组,您正在修改它。因此

puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES
产生同样的结果

在第二种情况下,您正在执行
a |=b
,这是
a=a | b
的缩写。这将为类
Bar
创建一个名为
ATTRIBUTES
的新数组。因此

puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES
产生不同的结果

在这个问题中,您可以阅读更多关于Ruby赋值运算符的信息

编辑

Ruby数组使用
&
|
运算符实现了一小部分set操作

单管,
|
执行联合操作,即仅添加唯一的元素

a = [:foo, :bar, :baz]
a |= [:baz, :buz] # => [:foo, :bar, :baz, :buz]

ruby中的常量有点用词不当。重新指定常量会产生警告:

Foo=1
Foo=2
(irb):5: warning: already initialized constant Foo
但是没有什么能阻止你改变实际值本身,而推送就是这样。如果你想防止这种情况发生,那么你可以冻结数组,即

class LibraryItem    
  ATTRIBUTES = ['title', 'authors', 'location'].freeze
end
尝试改变数组现在将引发异常。但只有数组被冻结,因此您可以执行以下操作

LibraryItem::ATTRIBUTES.first.upcase!

(假设您没有打开冻结字符串文本),并且允许进行更改。除了单独冻结字符串(或者在ruby 2.3及更高版本上打开该文件的冻结字符串文本),我不知道有什么方法可以解决此问题

在第一个示例中,
属性
在这两种情况下都引用相同的数组,在一个位置修改它意味着另一个位置也会看到更改。在第二个示例中,您将为
条形图创建一个新数组,而不是更改共享的数组,这会导致您想要的行为。因此,赋值使所有更改都不同ence?这意味着如果我的类get是子类,任何子类都可以更改“常量”?这段代码不可编译。@QPaysTaxes Ruby是一种解释语言。@RyanBemrose哎呀,是的。我的意思是说第一个会引起语法错误。是的,我的错。我不需要重温赋值运算符,但我确实需要重温常量的概念……那就是nks,这澄清了很多事情,冻结每一个都不难——你只要做
=[…]映射(&:freeze!)。冻结!
Er,只是
freeze
,而不是
freeze!
。对不起。
LibraryItem::ATTRIBUTES.first.upcase!