简体   繁体   中英

When to use constants instead of instance variables in Ruby?

I understand that instance variables are mean to be states, and constants are meant to be constant. Is there any reason (besides convention) to use a constant instead of an instance variable? Is there a memory/speed advantage to using constants?

There's a few things to consider here:

  • Will the value change within the life-cycle of an object?
  • Will you need to override the value in sub-classes?
  • Do you need to configure the value at run-time?

The best kind of constants are those that don't really change short of updating the software:

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

Generally you use these constants internally in the class and avoid sharing them. When you share them you're limited in how they're used. For example, if another class referenced ExampleClass::STATES then you can't change that structure without changing other code.

You can make this more abstract by providing an interface :

class ExampleClass
  def self.states
    STATES
  end
end

If you change the structure of that constant in the future you can always preserve the old behaviour:

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

  def self.states
    STATES.keys
  end
end

When you're talking about instance variables you mean things you can configure:

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

Constants are great in that they're defined once and used for the duration of the process, so technically they're faster. Instance variables are still pretty quick, and are often a necessity as illustrated above.

Constants, unlike instance variables, are global. And they will at least complain if you try to re-assign their value.

While there might be a theoretical difference in memory/speed, it will be irrelevant in practice.

You may not realize this, but classes and modules are considered constants.

pry(main)> Foo
NameError: uninitialized constant Foo

The best advice I can give as to when you should use constants are when they are exactly that, constant. For example, if I was making a scope in rails to find all the of recent Foo s for instance, I would create a constant that shows what recent is.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM