6 ответов:
ваша проблема заключается в том, что каждый раз при запуске метода вы присваиваете новое значение константе. Это не допускается, так как это делает константу непостоянной; даже если содержание строки одинаковы (на данный момент, во всяком случае), фактическая строка объект сам по себе отличается каждый раз, когда вызывается метод. Например:
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"если вы действительно хотите изменить значение константы в методе, и ваша константа является строкой или массивом, вы можете "обмануть" и использовать
#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"
поскольку константы в 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
в Ruby любая переменная, имя которой начинается с заглавной буквы, является константой, и вы можете назначить ее только один раз. Выбрать один из следующих вариантов:
class MyClass MYCONSTANT = "blah" def mymethod MYCONSTANT end end class MyClass def mymethod my_constant = "blah" end end
константы в ruby не могут быть определены внутри методов. см. комментарии в нижней части этой страницы, например
вы не можете назвать переменную с заглавными буквами, или Ruby будет считать ее константой и захочет, чтобы она сохраняла свое значение постоянным, и в этом случае изменение ее значения было бы ошибкой "ошибка динамического назначения константы". С нижним регистром должно быть хорошо
class MyClass def mymethod myconstant = "blah" end end
Ruby не нравится, что вы назначаете константу внутри метода, потому что это риск повторного назначения. Несколько ответов SO передо мной дают альтернативу назначению его вне метода, но в классе, который является лучшим местом для его назначения.
Comments