def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
也许如果您解释了您的用例 - 为什么要在方法中更改常量的值 - 我们可以帮助您实现更好的实现 .
也许你宁愿在课堂上有一个实例变量?
class MyClass
class << self
attr_accessor :my_constant
end
def my_method
self.class.my_constant = "blah"
end
end
p MyClass.my_constant #=> nil
MyClass.new.my_method
p MyClass.my_constant #=> "blah"
class MyClass
def my_method
self.class.const_set(:MY_CONSTANT, "foo")
end
end
MyClass::MY_CONSTANT
#=> NameError: uninitialized constant MyClass::MY_CONSTANT
MyClass.new.my_method
MyClass::MY_CONSTANT #=> "foo"
尽管如此,const_set isn 't something you should really have to resort to under normal circumstances. If you'不确定您是否真的想以这种方式分配常量,您可能需要考虑以下其中一种选择:
类变量
类变量在很多方面表现得像常量 . 它们是类的属性,可以在定义它们的类的子类中访问它们 .
不同之处在于类变量是可修改的,因此可以在没有问题的情况下分配给内部方法 .
class MyClass
def self.my_class_variable
@@my_class_variable
end
def my_method
@@my_class_variable = "foo"
end
end
class SubClass < MyClass
end
MyClass.my_class_variable
#=> NameError: uninitialized class variable @@my_class_variable in MyClass
SubClass.my_class_variable
#=> NameError: uninitialized class variable @@my_class_variable in MyClass
MyClass.new.my_method
MyClass.my_class_variable #=> "foo"
SubClass.my_class_variable #=> "foo"
类属性
类属性是一种“类上的实例变量” . 它们的行为有点像类变量,除了它们的值不与子类共享 .
class MyClass
class << self
attr_accessor :my_class_attribute
end
def my_method
self.class.my_class_attribute = "blah"
end
end
class SubClass < MyClass
end
MyClass.my_class_attribute #=> nil
SubClass.my_class_attribute #=> nil
MyClass.new.my_method
MyClass.my_class_attribute #=> "blah"
SubClass.my_class_attribute #=> nil
SubClass.new.my_method
SubClass.my_class_attribute #=> "blah"
有 are 合法用例,其中可能真的需要更改"constant's"值:例如,从类似REPL的提示循环重新加载ARGV,然后通过更多(后续)OptionParser.parse重新运行ARGV!打电话 - 瞧!给"command line args"一个全新的动态实用程序 .
实际问题要么是推定假设"ARGV must be a constant",要么是在optparse自己的初始化方法中,它将ARGV的赋值硬编码到实例var @default_argv进行后续处理 - 该数组(ARGV)确实应该是一个参数,鼓励在适当的情况下重新解析和重复使用 . 适当的参数化,以及适当的默认值(例如,ARGV)将避免需要更改"constant" ARGV . 只有2¢ - 思考...
7 回答
您的问题是,每次运行该方法时,您都要为常量赋值 . 这是不允许的,因为它使常数不恒定;即使字符串的内容相同(暂时,无论如何),每次调用方法时,实际的字符串对象本身都是不同的 . 例如:
也许如果您解释了您的用例 - 为什么要在方法中更改常量的值 - 我们可以帮助您实现更好的实现 .
也许你宁愿在课堂上有一个实例变量?
如果你真的想要在方法中更改常量的值,并且你的常量是一个String或一个数组,你可以'cheat'并使用
#replace
方法使对象获取一个新值而不实际更改对象:因为Ruby中的常量并不是要改变,所以Ruby不鼓励你在可能多次执行的代码部分中分配它们,例如内部方法 .
在正常情况下,您应该在类本身内部定义常量:
如果由于某种原因你确实需要在方法中定义一个常量(也许是某种类型的元编程),你可以使用const_set:
尽管如此,const_set isn 't something you should really have to resort to under normal circumstances. If you'不确定您是否真的想以这种方式分配常量,您可能需要考虑以下其中一种选择:
类变量
类变量在很多方面表现得像常量 . 它们是类的属性,可以在定义它们的类的子类中访问它们 .
不同之处在于类变量是可修改的,因此可以在没有问题的情况下分配给内部方法 .
类属性
类属性是一种“类上的实例变量” . 它们的行为有点像类变量,除了它们的值不与子类共享 .
实例变量
为了完整起见,我应该提一下:如果你需要分配一个只能在你的类被实例化后才能确定的值,那么你很可能实际上正在寻找一个普通的旧实例变量 .
在Ruby中,名称以大写字母开头的任何变量都是常量,您只能分配一次 . 选择以下替代方案之一:
ruby中的常量不能在方法内定义 . See the notes at the bottom of this page, for example
你不能用大写字母命名变量,或者Ruby会将它作为常量,并希望它保持它的值不变,在这种情况下,改变它的值将是一个错误,即“动态常量赋值错误” . 小写应该没问题
Ruby不喜欢你在方法内部分配常量,因为它有重新分配的风险 . 在我之前的几个SO答案给出了在方法之外分配它的替代方案 - 但是在类中,这是分配它的更好的地方 .
非常感谢Dorian和Phrogz提醒我关于数组(和散列)方法#replace,它可以“替换数组或散列的内容” .
CONSTANT的值可以更改,但有一个恼人的警告,这是Ruby的一些概念性错误步骤 - 这些应该是完全不可变的,或完全抛弃不变的想法 . 从编码员的角度来看,常量是声明性的和有意的,向其他人发出的信号是“一旦声明/分配,这个值就真的不可改变” .
但有时候一个“明显的宣言”实际上会阻止其他未来有用的机会 . 例如...
有 are 合法用例,其中可能真的需要更改"constant's"值:例如,从类似REPL的提示循环重新加载ARGV,然后通过更多(后续)OptionParser.parse重新运行ARGV!打电话 - 瞧!给"command line args"一个全新的动态实用程序 .
实际问题要么是推定假设"ARGV must be a constant",要么是在optparse自己的初始化方法中,它将ARGV的赋值硬编码到实例var @default_argv进行后续处理 - 该数组(ARGV)确实应该是一个参数,鼓励在适当的情况下重新解析和重复使用 . 适当的参数化,以及适当的默认值(例如,ARGV)将避免需要更改"constant" ARGV . 只有2¢ - 思考...