class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
给我错误:
SyntaxError:动态常量赋值错误
为什么这被视为动态常数?我只是给它分配一个字符串。
答案 0 :(得分:125)
您的问题是,每次运行该方法时,都会为常量赋值。这是不允许的,因为它使常数不恒定;即使字符串的内容是相同的(暂时,无论如何),每次调用该方法时,实际字符串 object 本身都是不同的。例如:
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"
如果确实想要在方法中更改常量的值,并且常量是String或Array,则可以“作弊”并使用#replace
方法使对象在不实际更改对象的情况下获取新值:
class MyClass
BAR = "blah"
def cheat(new_bar)
BAR.replace new_bar
end
end
p MyClass::BAR #=> "blah"
MyClass.new.cheat "whee"
p MyClass::BAR #=> "whee"
答案 1 :(得分:65)
因为Ruby中的常量不是要改变的,所以Ruby不鼓励你在可能多次执行的代码部分中分配它们,例如在方法内部。
在正常情况下,您应该在类本身内定义常量:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
如果由于某种原因你确实需要在方法中定义一个常量(可能是某种类型的元编程),你可以使用const_set
:
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
并不是你在正常情况下真正需要诉诸的东西。如果您不确定确实是否希望以这种方式分配常量,您可能需要考虑以下其中一种选择:
类变量在很多方面表现得像常量。它们是类的属性,可以在它们定义的类的子类中访问。
不同之处在于类变量是可修改的,因此可以在没有问题的情况下分配给内部方法。
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"
为了完整起见,我应该提一下:如果你需要分配一个只能在你的类被实例化后才能确定的值,那么你很可能真的在寻找一个普通的旧实例变量。
class MyClass
attr_accessor :instance_variable
def my_method
@instance_variable = "blah"
end
end
my_object = MyClass.new
my_object.instance_variable #=> nil
my_object.my_method
my_object.instance_variable #=> "blah"
MyClass.new.instance_variable #=> nil
答案 2 :(得分:26)
在Ruby中,名称以大写字母开头的任何变量都是常量,您只能分配一次。选择以下替代方案之一:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
答案 3 :(得分:14)
ruby中的常量不能在方法内定义。 See the notes at the bottom of this page, for example
答案 4 :(得分:0)
你不能用大写字母命名一个变量,否则Ruby会认为它是一个常数,并希望它保持它的值不变,在这种情况下改变它的值将是一个错误&#34;动态常数赋值错误&#34;。小写应该没问题
class MyClass
def mymethod
myconstant = "blah"
end
end
答案 5 :(得分:0)
Ruby不喜欢您在方法内部分配常量,因为它有重新分配的风险。在我之前有几个SO答案提供了在方法外部分配它的替代方法,但是在类中,这是分配它的更好位置。
答案 6 :(得分:0)
非常感谢Dorian和Phrogz提醒我有关数组(和哈希)方法#replace的信息,该方法可以“替换数组或哈希的内容。”
关于常量值可以更改但带有令人讨厌的警告的观念,是Ruby少数概念上的失误之一-这些失误应该是完全不变的,或者完全抛弃了不变的想法。从编码者的角度来看,常数是声明性的和有意的,向其他人发出信号,即“一旦声明/分配,此值实际上是不可更改的。”
但有时“明显的声明”实际上会排除其他未来有用的机会。例如...
在合法的使用案例中,可能确实需要更改“常量”的值:例如,从类似于REPL的提示循环中重新加载ARGV,然后通过更多方式重新运行ARGV(随后)OptionParser.parse!电话-瞧!为“命令行参数”提供了一个全新的动态实用程序。
实际问题是或,并采用optparse自己的initialize方法中的“ ARGV必须为常数”,或,该方法硬编码ARGV的分配实例var @default_argv进行后续处理-该数组(ARGV)实际上应该是一个参数,在适当的情况下鼓励重新解析和重用。适当的参数设置以及适当的默认值(例如ARGV)将避免需要更改“恒定” ARGV。仅有价值2美分的想法...