Ruby - В чем разница между определением константы с использованием 'const_set' и именем константы с простой заглавной буквой в классе? - PullRequest
2 голосов
/ 12 марта 2020

Я работаю над приложением Rails, где в одном классе константы определены с использованием const_set constant_name, value.

Я знаю, что мы можем определить константы непосредственно в классе, просто указав имя CAPITALIZE для константы с ее значением, например, следующим образом

class A
 RANDOM_CONSTANT = 1
end

, в чем разница между определением констант с помощью const_set а просто так, как я объявил в классе A?

Ответы [ 3 ]

4 голосов
/ 12 марта 2020

Я могу добавить к ответу @amadan, что этот метод, как и другие, например const_get, method_missing, define_method et c, является частью инструментов для метапрограммирования в ruby.

Например:

  1. #const_get

Допустим, у нас есть такой модуль Foo со списком констант: BOO, BAR, BAZ

module Foo
  BAR = 1
  BAZ = 2
  BOO = 3
end

теперь нам нужно распечатать все это, мы можем сделать это динамически или вручную:

def print_dynamically
  Foo.constants.each do |const| 
    p Foo.const_get(const)
  end
end

def print_manually
  p Foo::BAR
  p Foo::BAZ
  p Foo::BOO
end

> print_dynamically
=> 1
=> 2
=> 3

> print_manually
=> 1
=> 2
=> 3
#method_missing

Допустим, у нас есть такой класс Foo, и мы хотим добавить дружественный отлов ошибок для NoMethodError

class Foo
  def boo
    puts 'boo'
  end

  def method_missing(method_name)
    puts "sorry, method: ##{method_name} not defined."
    puts "Here is a list of public methods:"
    # here we take all defined public methods from class Foo except `#method_missing`
    p public_methods(false).reject { |n| n == :method_missing } 
  end
end

> foo = Foo.new
> foo.boo
=> boo
> foo.bar
=> sorry, method: #bar not defined.
=> Here is a list of public methods:
=> [:boo]
#define_method

Допустим, нам нужно определить некоторый список простых (или нет) методов, и мы не хотим просто скопировать и вставить его:

вместо:

class Foo
  def foo
    puts "foo"
  end
  def boo
    puts "boo"
  end
  def bar
    puts "bar"
  end
end

> foo.foo
=> foo
> foo.boo
=> boo
> foo.bar
=> bar

вы можете просто написать его так:

class Foo
  %i[foo boo bar].each do |method_name|
    define_method(method_name) { puts "#{method_name}" }
  end
end

> foo.foo
=> foo
> foo.boo
=> boo
> foo.bar
=> bar

Резюме: Из приведенных ниже примеров видно, что Ruby предоставляет нам множество инструментов для динамического создания методов, их получения, получения констант и их установки.

PS Это далеко не все методы, это всего лишь несколько из них, но я думаю, этого достаточно, чтобы показать, что вы можете делать с инструментами метапрограммирования в ruby.

3 голосов
/ 12 марта 2020
class A
  RANDOM_CONSTANT = 1
end

проще писать и читать. Это должен быть предпочтительный способ установки константы.

constant_name = 'RANDOM_CONSTANT'
A.const_set(constant_name, 1)

будет работать, когда имя константы генерируется динамически, и, следовательно, более гибко. Обычно вы используете его только тогда, когда хотите сделать несколько метапрограммирующих магов c.

Кроме того, они эквивалентны.

1 голос
/ 12 марта 2020

Насколько я знаю, нет никакой разницы, так что это:

class A; end
A.const_set('RANDOM_CONSTANT', 1)

эквивалентно:

class A
  RANDOM_CONSTANT = 1
end
...