首页 文章

动态常量赋值

提问于
浏览
116
class MyClass
  def mymethod
    MYCONSTANT = "blah"
  end
end

给我错误:

SyntaxError:动态常量赋值错误

为什么这被视为动态常数?我只是给它分配一个字符串 .

7 回答

  • 0

    您的问题是,每次运行该方法时,您都要为常量赋值 . 这是不允许的,因为它使常数不恒定;即使字符串的内容相同(暂时,无论如何),每次调用方法时,实际的字符串对象本身都是不同的 . 例如:

    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或一个数组,你可以'cheat'并使用 #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"
    
  • 61

    因为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 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"
    

    实例变量

    为了完整起见,我应该提一下:如果你需要分配一个只能在你的类被实例化后才能确定的值,那么你很可能实际上正在寻找一个普通的旧实例变量 .

    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
    
  • 119

    在Ruby中,名称以大写字母开头的任何变量都是常量,您只能分配一次 . 选择以下替代方案之一:

    class MyClass
      MYCONSTANT = "blah"
    
      def mymethod
        MYCONSTANT
      end
    end
    
    class MyClass
      def mymethod
        my_constant = "blah"
      end
    end
    
  • 22

    ruby中的常量不能在方法内定义 . See the notes at the bottom of this page, for example

  • 0

    你不能用大写字母命名变量,或者Ruby会将它作为常量,并希望它保持它的值不变,在这种情况下,改变它的值将是一个错误,即“动态常量赋值错误” . 小写应该没问题

    class MyClass
      def mymethod
        myconstant = "blah"
      end
    end
    
  • 13

    Ruby不喜欢你在方法内部分配常量,因为它有重新分配的风险 . 在我之前的几个SO答案给出了在方法之外分配它的替代方案 - 但是在类中,这是分配它的更好的地方 .

  • 0

    非常感谢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¢ - 思考...

相关问题