动机
在[bootrAils]启动程序中,我们没有很多Ruby常量。然而,当需要时,知道它们是如何工作的总是好的。
"常量 "是不允许改变的变量。让我们来看看是怎样的。在这篇文章中,我们将使用ruby控制台,如果你在Rails环境中,你可以通过输入bin/rails console 。
如何定义一个Ruby常量
常量以大写字母开头。
例子:
Boiling = 100 # valid
BOILING = 100 # valid
boiling = 100 # invalid
定义在类或模块内的常量可以从内部直接访问。那些定义在类或模块之外的常量仍然可以被全局访问。
例子:
class Water
ICE = 0
BOIL = 100
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
你可以注意到,ICE和BOIL可以从定义它们的类中自由访问。从外部:
Water::ICE
# => 0
Water::BOIL
# => 100
Water.new.show
# => Celsius temperature for becoming ice is 0
# => Celsius temperature for becoming steam is 100
会失败的Ruby常量
常量不能被定义在一个方法里面。
例子:
class Water
def show
ICE = 0
BOIL = 100
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
# Traceback (most recent call last):
# SyntaxError ((irb):117: dynamic constant assignment)
# ICE = 0
常量不能以小写字母开头。
class Water
ice = 0 # ! fail ! Constant cannot start with lowercase
boil = 100 # ! fail ! Constant cannot start with lowercase
def show
puts "Celsius temperature for becoming ice is #{ice}"
puts "Celsius temperature for becoming steam is #{boil}"
end
end
这将在调用时产生以下错误。
Water::ice
Traceback (most recent call last):
1: from (irb):87:in `<main>'
NoMethodError (undefined method `ice' for Water:Class)
未初始化的常量错误
如果你使用Ruby-on-Rails或其他框架编程,这种错误经常发生。它通常意味着模块中的一个类或常量没有被找到。你可以很容易地在你的电脑上重新创建这个错误。
class Water
ICE = 0
BOIL = 100
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
然后尝试简单地访问一个不存在的常量。
irb(main):131:0> Water::ICE
0
irb(main):132:0> Water::UNEXISTING
Traceback (most recent call last):
1: from (irb):132:in `<main>'
NameError (uninitialized constant Water::UNEXISTING)
改变...一个Ruby常量
如果你来自其他语言,这将是一件令人不安的事情:Ruby常量可以被改变而不会产生任何错误。
Water::ICE = 42
# => warning: already initialized constant Water::ICE
Water::ICE
# => 42
一个警告被提出,但程序仍然继续。
如果你想避免这种默认行为,你必须freeze 你的常量。
在这个例子中,我打算冻结......冰块。
class Water
ICE = 0.freeze
BOIL = 100.freeze
def show
puts "Celsius temperature for becoming ice is #{ICE}"
puts "Celsius temperature for becoming steam is #{BOIL}"
end
end
这其实并不奏效,因为你仍然可以使Water::ICE = 42 ,并且有一个简单的警告。
一个Ruby常量实际上并不是不可改变的,而且你不能冻结一个变量。