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