【发布时间】:2009-12-30 00:25:44
【问题描述】:
Ruby 常量的真正含义是什么?以下代码未显示任何“常量”属性。警告在那里,但我仍然可以更改 A 所指的内容。
A = 1
puts A # => 1
A = 2 # warning: already initialized constant A
puts A # => 2
还是说 Ruby 常量只是一个指示,没有任何强制执行?
【问题讨论】:
Ruby 常量的真正含义是什么?以下代码未显示任何“常量”属性。警告在那里,但我仍然可以更改 A 所指的内容。
A = 1
puts A # => 1
A = 2 # warning: already initialized constant A
puts A # => 2
还是说 Ruby 常量只是一个指示,没有任何强制执行?
【问题讨论】:
没错,constants 就像 ruby 中的 variables,但是如果你改变它们,你会得到一个警告。
此外,与单纯的变量有一个区别:您可以访问常量,即使它们是在另一个类或模块中定义的,例如给定这个 sn-p:
module Constants
PI = 3,1415
other = "variable"
end
您可以通过Constants::PI 联系PI,而Constants::other 将不起作用。
【讨论】:
是的,除了打印警告外,没有强制使用 Ruby 常量。
【讨论】:
没错——赋值给一个常量是一个警告,而不是一个错误; “常量”只是指示您应该如何使用某些东西的指标,而不是您确实以这种方式使用它的规则。
这在静态编程世界中听起来可能很可怕,但它在各种元编程工具中非常有用,它可以实现静态语言中完全不可能的事情。
也就是说,如果您真的想确保人们不会对您的推荐信感到手足无措,您可以使用Object#freeze。用这个来改变参考指向的东西还是可以的;您只是无法更改引用本身的内容:
irb(main):001:0> class Fruit; attr_accessor :name; end
=> nil
irb(main):002:0> f = Fruit.new
=> #<Fruit:0xb7e06570>
irb(main):003:0> f.name = "apple"
=> "apple"
irb(main):004:0> f.freeze # After freeze, can't touch this Fruit.
=> #<Fruit:0xb7e06570 @name="apple">
irb(main):005:0> f.name = "banana"
TypeError: can't modify frozen object # Kablammo!
from (irb):5:in `name='
from (irb):5
但这没关系:
irb(main):006:0> f = Fruit.new
=> #<Fruit:0xb7dfed84>
irb(main):007:0> f.name = "banana"
=> "banana"
【讨论】:
Fruit。所以应该是Fruit.freeze 而不是f.freeze
freeze 可以(您可以在任何对象上使用freeze)。
“常量”确实是用词不当,Ruby 的“常量”最重要的方面不是它们的不变性,而是它们的查找规则。
见:http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/
【讨论】:
常量用于存储不应更改的值。他们的名字必须以大写字母开头。按照惯例,大多数常量名称都以大写字母书写,并带有下划线作为单词分隔符,例如 SOME_CONSTANT。
类中定义的常量可以被该类的所有方法访问。在类之外创建的那些可以全局访问(在任何方法或类中)。
class Car
WHEELS = 4
def initialize
puts WHEELS
end
end
c = Car.new # Output: 4
请注意,Ruby 不会阻止我们更改常量的值,它只会发出警告。
SOME_CONSTANT = "foo"
SOME_CONSTANT = "bar"
warning: already initialized constant SOME_CONSTANT
warning: previous definition of SOME_CONSTANT was here
在 Ruby 中,所有类名和模块名都是常量,但约定要求它们应该用驼峰写法,例如 SomeClass。
通过使用 ::(双冒号)运算符,可以从类外部访问常量,甚至在另一个类中。要从 Car 类外部访问 WHEELS 常量,我们将使用 Car::WHEELS。 :: 运算符允许从定义它们的类或模块外部访问常量、公共实例方法和类方法。
名为 private_constant 的内置方法使常量成为私有的(只能在创建它们的类中访问)。语法如下:
class Car
WHEELS = 4
private_constant:WHEELS
end
Car::WHEELS # Output: NameError: private constant Car::WHEELS referenced
【讨论】:
如果您来自其他编程语言,Ruby 处理常量的方式与您可能习惯的方式不同。通常,常量采用在整个应用程序中不会改变的值。语法是在命名常量时使用所有大写字母,以便应用程序知道如何处理它。例如,要设置一个常量来容纳一支棒球队,您可以这样声明:
TEAM = "Angels"
我知道你知道这么多,请耐心等待。通常,其他编程语言不允许您更改 TEAM 的值。但是,Ruby 不会阻止您,它会获取分配给常量的最后一个值。在上面的示例中,我可以将其值更改为:
TEAM = "Athletics"
其他编程语言要么抛出错误,要么打印 Angels 的值。但是,Ruby 会打印出值 Athletics,因为这是分配给变量 TEAM 的最后一个值。此外,它会给出一条警告消息,指出该常量已经初始化并已更改,因为更改常量被认为是一种糟糕的编程习惯。但是,它仍然允许您进行更改并遵循相信开发人员做出正确编程决策的 Ruby 约定。因此,在 Ruby 中使用常量时要小心,因为它们可以被覆盖。
【讨论】: