Динамическое назначение констант



class MyClass
def mymethod
MYCONSTANT = "blah"
end
end


дает мне ошибку:




SyntaxError: динамическая ошибка назначения констант




почему это считается динамической константой? Я просто присваиваю ему строку.

474   6  

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

    Ничего не найдено.