动态常量赋值

the*_*ror 130 ruby

class MyClass
  def mymethod
    MYCONSTANT = "blah"
  end
end
Run Code Online (Sandbox Code Playgroud)

给我错误:

SyntaxError:动态常量赋值错误

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

Phr*_*ogz 130

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

def foo
  p "bar".object_id
end

foo #=> 15779172
foo #=> 15779112
Run Code Online (Sandbox Code Playgroud)

也许如果您解释了您的用例 - 为什么要在方法中更改常量的值 - 我们可以帮助您实现更好的实现.

也许你宁愿在课堂上有一个实例变量?

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"
Run Code Online (Sandbox Code Playgroud)

如果你真的想要在方法中更改常量的值,并且你的常量是一个String或一个数组,你可以"欺骗"并使用该#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"
Run Code Online (Sandbox Code Playgroud)

  • OP从未说过他想要改变常数的值,而只想分配一个值.导致此Ruby错误的常见用例是当您从其他运行时资产(变量,命令行参数,ENV)在方法中构建值时,通常在构造函数中,例如`def initialize(db,user,password) DB = Sequel.connect("postgres://#{user}:#{password} @ localhost /#{db}")end`.这是Ruby没有简单方法的案例之一. (19认同)
  • @ArnaudMeuret对于这种情况,你需要一个实例变量(例如`@ variable`),而不是常量.否则,每次实例化该类的新实例时,您都将重新分配`DB`. (2认同)
  • @ Ajedi32这种情况通常来自外部约束,而不是设计选择,例如我的续集示例.我的观点是Ruby在某些范围内允许为常量赋值,而不允许其他范围.过去由开发人员明智地选择何时执行分配.Ruby改变了这一点.不是每个人都好. (2认同)
  • @ArnaudMeuret我会承认我之前从未使用过Sequel,所以我不能100%肯定地说这个,但只是看了一下Sequel的文档我什么也没看到你必须分配`Sequel.connect`的结果到一个名为DB的常量.事实上,文档明确说明这只是一个建议.这听起来不像是对我的外在约束. (2认同)

Aje*_*i32 66

因为Ruby中的常量并不是要改变,所以Ruby不鼓励你在可能多次执行的代码部分中分配给它们,比如内部方法.

在正常情况下,您应该在类本身内部定义常量:

class MyClass
  MY_CONSTANT = "foo"
end

MyClass::MY_CONSTANT #=> "foo"
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因你确实需要在方法中定义一个常量(也许是某种类型的元编程),你可以使用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"
Run Code Online (Sandbox Code Playgroud)

但是,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"
Run Code Online (Sandbox Code Playgroud)

类属性

类属性是一种"类上的实例变量".它们的行为有点像类变量,除了它们的值不与子类共享.

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"
Run Code Online (Sandbox Code Playgroud)

实例变量

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

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
Run Code Online (Sandbox Code Playgroud)


Dav*_*son 30

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

class MyClass
  MYCONSTANT = "blah"

  def mymethod
    MYCONSTANT
  end
end

class MyClass
  def mymethod
    my_constant = "blah"
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 谢天谢地有人提到“名称以大写字母开头的任何变量都是常量!” (2认同)
  • @ubienewbie 完全可以。我一直认为它必须是“全部”大写,而不仅仅是第一个字母。当将变量分配给“Struct.new”时,这非常有用。将第一个字母大写使其成为常量,这让 Ruby 很生气。谢谢! (2认同)

chr*_*nda 14

ruby中的常量不能在方法内定义.例如,请参阅本页底部的注释