在 Ruby 中什么时候使用常量而不是实例变量?

When to use constants instead of instance variables in Ruby?

我明白实例变量是状态,常量是常量。有什么理由(除了约定之外)使用常量而不是实例变量吗?使用常量有 memory/speed 优势吗?

与实例变量不同,常量是全局的。如果您尝试重新分配他们的价值,他们至少会抱怨。

虽然 memory/speed 中可能存在理论上的差异,但在实践中是无关紧要的。

这里有几点需要考虑:

  • 值会在对象的生命周期内改变吗?
  • 您是否需要覆盖子 classes 中的值?
  • 是否需要在运行时配置值?

最好的常量是那些只更新软件就不会真正改变的常量:

class ExampleClass
  STATES = %i[
    off
    on
    broken
  ].freeze
end

通常您在 class 内部使用这些常量并避免共享它们。当您共享它们时,它们的使用方式会受到限制。例如,如果另一个 class 引用了 ExampleClass::STATES,那么您不能在不更改其他代码的情况下更改该结构。

您可以通过提供 接口 使它更抽象:

class ExampleClass
  def self.states
    STATES
  end
end

如果您将来更改该常量的结构,您始终可以保留旧行为:

class ExampleClass
  STATES = {
    on: 'On',
    off: 'Off',
    broken: 'Broken'
  }.freeze

  def self.states
    STATES.keys
  end
end

当您谈论实例变量时,您指的是您可以配置的东西:

class ConfigurableClass
  INITIAL_STATE_DEFAULT = :off

  def self.initial_state
    @initial_state || INITIAL_STATE_DEFAULT
  end

  def self.initial_state=(value)
    @initial_state = value ? value.to_sym
  end
end

常量很棒,因为它们定义一次并在整个过程中使用,因此从技术上讲它们更快。实例变量仍然非常快,并且通常是必要的,如上所示。

您可能没有意识到这一点,但是 类 和模块被认为是常量。

pry(main)> Foo
NameError: uninitialized constant Foo

关于何时应该使用常量,我能给出的最佳建议是当它们确实是常量时。例如,如果我在 rails 中创建范围以查找最近的所有 Foo,我将创建一个常量来显示最近的内容。

class Foo < ActiveRecord::Base
  DAYS_TILL_OLD = 7.days

  scope :recent, -> { where "created_at > ?", DateTime.now - DAYS_TILL_OLD  }
end