【问题标题】:Ruby class constants and inheritance mysteryRuby 类常量和继承之谜
【发布时间】:2016-11-11 19:07:56
【问题描述】:

为什么以下两个代码 sn-ps 不会产生相同的输出? push|= 之间的区别很棘手。我想|= 是一个任务可能会有所作为?最重要的是,常量实际上以后不会发生变化,我猜不是吗?

代码来自this question 的答案。你可以看到它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 在这两种情况下都引用了 same 数组,在一个地方修改它意味着另一个地方也会看到更改。在第二个中,您正在为 Bar 创建一个新数组,而不是更改共享数组,这会产生您想要的行为。
  • 所以是分配决定了一切?这意味着如果我的类得到子类,任何子类都可以更改“常量”?
  • 这段代码无法编译。
  • @QPaysTaxes Ruby 是一种解释型语言。
  • @RyanBemrose 哎呀,是的。我的意思是说第一个会引发语法错误。

标签: ruby class constants immutability


【解决方案1】:

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

puts LibraryItem::ATTRIBUTES
puts LibraryBook::ATTRIBUTES

产生相同的结果。

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

puts Foo::ATTRIBUTES
puts Bar::ATTRIBUTES

产生不同的结果。

您可以在此问题中阅读有关 Ruby 赋值运算符 的更多信息。 Ruby |= assignment operator

编辑

Ruby 数组使用&amp;| 运算符实现了一个小的集合操作。

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

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

【讨论】:

  • 是的,我的错。我不需要复习赋值运算符,但是关于 constants 的概念我显然...
【解决方案2】:

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 及更高版本上为该文件打开冻结字符串文字)之外,我不知道有什么解决方法

【讨论】:

  • 谢谢,这说明了很多事情
  • 冻结每一个都不会那么难——你只需要做= [ ... ].map(&amp;:freeze!).freeze!
  • 呃,只是freeze,而不是freeze!。对不起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
  • 2017-03-20
  • 2020-08-31
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
相关资源
最近更新 更多