Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

【完全ガイド】Rubyの定数とは?定義方法・スコープ・注意点を徹底解説

Rubyにおける定数とは?

Rubyの定数(constant)は、必ずアルファベットの大文字で始まる変数の一種です。メタプログラミングを利用しない限り、メソッドの外側でしか定義できません。

定数は「変更されるべきではない値」を扱うために用意されていますが、実はRuby自体はその変更を強制的に防ぐ仕組みを持っていません。

定数の基本的な書き方は次のとおりです

FRUIT = "orange"

定数はRubyプログラミングにおいて重要なトピックです。この記事では、定義方法からスコープの挙動まで、詳しく解説していきます!

定数の定義方法

定数の宣言には特別な記号や構文は必要ありません。先頭の文字を大文字にするだけでOKです。

以下はすべて有効な定数です

ABC = 1
Goo = 2
Foo = 3

ただし、メソッドの中では定数を定義できない点に注意してください。

メソッド内で定義しようとすると、次のようなエラーが発生します:

def the_method
  ABC = 1
end

# "dynamic constant assignment" エラー

定数はメソッドの外で定義しましょう。一般的には、クラスの先頭付近にまとめて記述すると可読性が高まり、他の開発者にも意図が伝わりやすくなります。

class RubyBlog
  URL    = "rubyguides.com"
  AUTHOR = "Jesus Castello"
end

クラス内のメソッドからは直接参照でき、クラスの外部からは :: を使ってアクセスできます:

p RubyBlog::AUTHOR

# "Jesus Castello"

定数のスコープについては、記事の後半でさらに詳しく説明します。

「uninitialized constant」エラーの原因と対処法

Ruby開発でよく目にするエラーのひとつがこちらです:

puts Foo
# "uninitialized constant Foo (NameError)"

このエラーは「定数が見つかりません」という意味だと捉えると理解しやすくなります。

このエラーを理解するうえで重要なポイントは、Rubyのクラス名もすべて定数であるという事実です。

Array
String
Hash

これらが定数として扱われるのは、先頭の文字が大文字だからです。

クラスを定義するとき、実際に行っているのは Class オブジェクトを生成し、それを定数に代入する処理です。そして、その定数名がクラス名になります。

なぜこれが重要なのでしょうか?

「uninitialized constant」エラーが出る最も多い原因は、定数を定義しているファイルやgemを require し忘れていることです。あるいは、単純に定数名のスペルミスというケースもあります。

エラーが出たら、まずこの2点を確認してみてください。

定数は変更できる(警告付き)

冒頭でも触れたとおり、Rubyの定数は実際には変更可能です。

ABC = 1
ABC = 2

ただし、この場合は次のような警告メッセージが表示されます:

2: warning: already initialized constant ABC

プログラム自体は動作しますが、このような書き方は避けるべきです。

定数の再代入を完全に防ぐ方法はありません。なぜなら、Rubyの変数はオブジェクトを格納する「容器」ではなく、オブジェクトへのポインタ(ラベル)にすぎないからです。

せいぜいできるのは、イミュータブル(不変)なオブジェクトを使うことです。

AUTHOR = "Jesus Castello".freeze

AUTHOR << "o"
# RuntimeError: can't modify frozen String

関連記事:Rubyのミュータビリティとfreezeメソッド

この例では、AUTHOR 定数が指し示す先を変えることは依然として可能です。freeze が守ってくれるのは、オブジェクトそのものの変更からだけです。

定数を操作するためのメソッド一覧

定数を扱うために用意されている専用メソッドがいくつかあります:

メソッド 説明
constants クラス内で定義されている定数の一覧をシンボルの配列で返す
const_get 定数の値を取得する。引数にはシンボルまたは文字列を指定
const_set 定数に値を設定する。引数は「定数名(シンボル)」と「値」の2つ
const_missing method_missing の定数版
const_defined? 指定した定数(シンボル)が定義済みなら true を返す
remove_const 定数を削除する
private_constant 定数をprivateにし、クラス外からの Class::ABC 形式のアクセスを不可能にする

これらのメソッドを使えば、メタプログラミング的なテクニックも実現できます。

module Food
  class Bacon; end
  class Chocolate; end
end

puts "Classes defined inside #{Food}:"

puts Food.constants

また、"Array" のような文字列から、実際のクラスオブジェクトを取得することもできます:

array_class = Object.const_get("Array")

ただしこの使い方には注意が必要です。文字列が params などのユーザー入力由来の場合、コードインジェクションの危険性があります。

Railsには constantize メソッドがあり、内部的には const_get と同じことを行いますが、セキュリティチェックは一切行われない点に留意してください。

チートシート

【完全ガイド】Rubyの定数とは?定義方法・スコープ・注意点を徹底解説

Rubyの定数スコープ

どのクラスにも属さないトップレベルで定義した定数は、プログラムのどこからでも参照できます。

また、定数は子クラスからも利用できます。

class A
  FOO = 1
end

class B < A
  def foo
    puts FOO
  end
end

B.constants

# [:FOO]

ネストしたモジュールやクラスの外側で定義された定数も、内側のクラスから参照できます。

module Food
  STORE_ADDRESS = "The moon"

  class Bacon
    def foo; puts STORE_ADDRESS; end
  end
end

fb = Food::Bacon.new
fb.foo

# "The moon"

Mix-inされたモジュールの定数

include で取り込んだモジュールの定数も利用できます:

module Mixin
  A = 123
end

class Product
  include Mixin

  puts A
end

# 123

これはモジュールを include した場合にのみ機能し、extend した場合には機能しません。

class Product
  extend Mixin

  puts A
end

# uninitialized constant Product::A

さらに重要なポイント

モジュールからincludeされたメソッドを使うとき、Rubyは定数を探す起点を「そのメソッドが定義されている場所」とします。

module Parent
  def print_value
    VALUE
  end
end

class Child
  include Parent

  VALUE = 1
end

# 動作する
p Child::VALUE

# uninitialized constant Parent::VALUE
p Child.new.print_value

この挙動は覚えておくと役立ちます!

モジュールのネストと定数の探索

ネストしたクラス(モジュールも同様)に関するもうひとつの例を見てみましょう。

class A
  FOO = 1
end

class A::B
  class C
    puts FOO
  end
end

ここで A::B という記法をショートカットとして使っていますが、問題があります。この書き方だと、クラス C から FOO に直接アクセスできないのです。

そのため、ネストは次のように書くのが安全です:

class A
  FOO = 1
end

class A
  class B
    class C
      puts FOO
    end
  end
end

最初の例でも ::A::FOO と書けば定数にアクセスできますが、クラス名を変更した場合にエラーになってしまいます。

::A::FOO という構文が機能するのは、先頭の :: がRubyに対して「トップレベルのスコープ(ArrayString などが定義されている場所)を探せ」と指示するからです。

動画解説

まとめ

この記事では、Rubyの定数について学びました。定数は興味深い挙動を持つ変数の一種で、値を変更することは可能ですが、その際には警告が表示されます。

また、クラス名も定数であること、そしてユーザー入力に対して const_get を使うのは避けるべきことも理解しましたね。

この記事が役に立ったら、ぜひシェアしてください。より多くの人が定数の仕組みを理解できますように!


  1. Bluetooth 5とは?知っておきたい新機能と特徴を徹底解説

    Wi-Fiと同様に、Bluetoothはスマートフォンをはじめとするあらゆるモバイルデバイスに欠かせない技術です。ファイルやデータの転送だけでなく、ワイヤレススピーカーやスポーツ用イヤホンなどの周辺機器との接続にも幅広く活用されています。 Bluetoothはコミュニケーションのあり方を変えただけでなく、多くのデバイスを大型からコンパクトへと進化させました。最新バージョンのBluetooth 5では、従来のバージョンでは実現できなかったさまざまなことが可能になっています。劇的な変革とまでは言えませんが、確かに新しい魅力がいくつも追加されています。それでは、Bluetooth 5がもたらす新機能

  2. PBMファイルとは?正体や開き方・変換方法をわかりやすく解説

    パソコンが身近な存在になって以来、テクノロジーとエンターテインメントの分野は目覚ましい成長を遂げてきました。その中でも最も一般的な娯楽のひとつが、写真をはじめとするメディアコンテンツです。現在の技術では、特定のファイルを開くために対応アプリケーションを探す手間はほとんどありません。しかし、画像やメディアファイルにはそれぞれ異なる種類があり、多様な拡張子が存在することを知っておくことは有益です。そのひとつである「PBM」という拡張子は、ここしばらくユーザーの間で注目を集めています。本記事では、PBMファイルの概要とその扱い方についてわかりやすくご紹介します。 PBMファイルとは? PBMは「P