読み込み中...

Rubyの定数とfreezeの使い方を解説!初心者が10ステップで完全理解するための徹底ガイド

Rubyの定数とfreezeメソッドを解説するイメージ画像 Ruby
この記事は約10分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

プログラミング初心者にとって、Rubyの定数やfreezeメソッドを理解し、適切に使用することは、コードの安全性を高め、バグを減らすために重要です。

この記事を読めば、Rubyの定数とfreezeメソッドの基本的な使い方から、応用的な使い方まで、初心者でもステップバイステップで理解することができます。

●Rubyの定数とは

Rubyには変数と定数という2つの値を保持する手段が存在します。

今回はそのうちの「定数」について詳しく解説します。

○定数の基本

定数は、その名の通り一度設定した値を変更することができない特性を持っています。

定数を使うことで、一度設定した値がプログラムの途中で意図せず変更されることを防ぎ、コードの安全性を高めることができます。

○定数の命名規則

Rubyでは、定数は全て大文字とアンダースコア(_)を使った名前をつけることが慣習となっています。

例えば、「MY_CONSTANT」のように名付けます。

●定数の使い方

では、具体的なコードを見ながら、定数の宣言と利用方法について学びましょう。

○サンプルコード1:定数の宣言と利用

ここでは定数を宣言し、それを利用する簡単なコードを紹介します。

下記の例では、’MY_CONSTANT’という名前の定数を宣言し、その値を表示しています。

# 定数の宣言
MY_CONSTANT = 'Hello, world!'

# 定数の利用
puts MY_CONSTANT  # => Hello, world!

このコードでは’MY_CONSTANT’という定数を作り、その値を’Hello, world!’に設定しています。

その後、putsを使って定数の値を表示しています。

○サンプルコード2:定数の再代入

Rubyでは、一度定義した定数に対して新たな値を代入すると、警告が出ます。

しかし、値自体は新たに代入された値に変わります。

# 定数の宣言
MY_CONSTANT = 'Hello, world!'

# 定数の再代入
MY_CONSTANT = 'Goodbye, world!'  # => warning: already initialized constant MY_CONSTANT

# 定数の利用
puts MY_CONSTANT  # => Goodbye, world!

この例では、一度定義した定数’MY_CONSTANT’に対して新たな値’Goodbye, world!’を代入しています。

その結果、警告が表示されますが、実際に定数の値は新たに代入された値に変わっています。

ここまでで、定数の基本的な使い方と、再代入による警告の出現について理解できたでしょう。

次に、Rubyのfreezeメソッドについて解説します。

●Rubyのfreezeメソッドとは

Rubyのfreezeメソッドは、オブジェクトを「凍結」するためのメソッドです。

凍結されたオブジェクトはその後、変更ができない状態になります。

○freezeメソッドの基本

freezeメソッドは、あらゆるオブジェクトに対して呼び出すことができます。

このメソッドを使用すると、そのオブジェクトは「凍結」され、その状態からは変更することができなくなります。

○freezeメソッドの仕組み

freezeメソッドはオブジェクトの内部状態を変更する操作をすべて防ぐようになります。

具体的には、オブジェクトへの新たなメソッドの追加や、既存のメソッドの変更、インスタンス変数への再代入などが防がれます。

●freezeメソッドの使い方

では、実際にfreezeメソッドを使ってみることで、その動作を理解してみましょう。

○サンプルコード3:オブジェクトのfreeze

下記のコードは、Stringオブジェクトに対してfreezeメソッドを呼び出し、その後でそのオブジェクトを変更しようとしています。

# オブジェクトのfreeze
str = 'Hello, world!'
str.freeze

# freezeされたオブジェクトの変更
str[0] = 'h'  # => Error: can't modify frozen String

このコードでは、まず文字列’Hello, world!’を変数strに代入し、その後でそのstrに対してfreezeメソッドを呼び出しています。

そして、その後でそのstrの最初の文字を’h’に変更しようとしていますが、strは既にfreezeされているのでエラーが発生します。

○サンプルコード4:freezeされたオブジェクトの挙動

freezeメソッドが呼び出された後のオブジェクトの挙動を詳しく見てみましょう。

下記のコードでは、Arrayオブジェクトに対してfreezeメソッドを呼び出し、その後でそのオブジェクトを変更しようとしています。

# Arrayオブジェクトのfreeze
arr = [1, 2, 3]
arr.freeze

# freezeされたオブジェクトの変更
arr << 4  # => Error: can't modify frozen Array

このコードでは、配列[1, 2,3]を変数arrに代入し、その後でそのarrに対してfreezeメソッドを呼び出しています。

そして、その後でそのarrに新たな要素4を追加しようとしていますが、arrは既にfreezeされているのでエラーが発生します。

これらの例から、freezeメソッドが呼び出された後のオブジェクトは、その状態からは変更することができないことがわかります。

しかし、freezeメソッドはオブジェクトの「表面」のみを凍結し、オブジェクトが参照している他のオブジェクトには影響を及ぼしません。

そのため、ネストしたオブジェクトに対しては、内部のオブジェクトまで凍結するためには、それぞれに対してfreezeメソッドを呼び出す必要があります。

●定数とfreezeメソッドの組み合わせ

Rubyの定数は、基本的には値の再代入が許されていません。

しかし、実際には警告を出すだけで、値の再代入自体は防げません。

これに対し、freezeメソッドを使うと、オブジェクト自体の変更を防ぐことができます。

これにより、定数が本当の意味で「定数」になるといえます。

では、具体的にどのように使うのか見てみましょう。

○サンプルコード5:定数にfreezeメソッドを適用する

下記のコードは、定数に対してfreezeメソッドを適用し、その後でその定数の値を変更しようとしています。

# 定数にfreezeメソッドを適用する
CONST = [1, 2, 3].freeze

# freezeされた定数の変更
CONST[0] = 4  # => Error: can't modify frozen Array

このコードでは、まず配列[1, 2, 3]を定数CONSTに代入し、その時点でその配列に対してfreezeメソッドを呼び出しています。

そして、その後でそのCONSTの最初の要素を4に変更しようとしていますが、CONSTは既にfreezeされているのでエラーが発生します。

これにより、定数が本当の意味で「定数」になるといえます。

次に、freezeメソッドの応用例について見てみましょう。

●応用例

freezeメソッドは、イミュータブルな(変更不能な)クラスを作る際にも活用できます。

イミュータブルなクラスを作ることで、そのクラスのインスタンスは作成後に変更されることなく、プログラムの動作を安定させることができます。

○サンプルコード6:freezeを使ったイミュータブルなクラスの作成

下記のコードは、freezeメソッドを用いてイミュータブルなクラスを作成しています。

# freezeを使ったイミュータブルなクラスの作成
class ImmutableClass
  attr_reader :value

  def initialize(value)
    @value = value
    freeze
  end
end

immutable_object = ImmutableClass.new('immutable')
immutable_object.value = 'mutable'  # => Error: can't modify frozen ImmutableClass

このコードでは、ImmutableClassというクラスを定義し、その中でinitializeメソッド(コンストラクタ)の最後でfreezeメソッドを呼び出しています。

そして、そのImmutableClassのインスタンスを作成し、そのインスタンスのvalue属性を変更しようとしていますが、そのインスタンスはfreezeされているのでエラーが発生します。

これにより、そのインスタンスは作成後には変更されることがなく、プログラムの動作を安定させることができます。

これらの例から、freezeメソッドはオブジェクトの変更を防ぐために使用できる強力なツールであることがわかります。

しかし、freezeメソッドを使用する際には注意点もあります。

●注意点と対処法

freezeメソッドはオブジェクトを凍結することができますが、そのオブジェクトが参照している他のオブジェクトまでは凍結しません。

また、freezeしたオブジェクトを変更しようとするとエラーが発生します。

これらの点に注意しながら、freezeメソッドを上手く活用していきましょう。

○定数の再代入の警告

Rubyの定数は、原則として再代入が許されていません。

しかし、実際には再代入自体は可能で、再代入を行うと警告が発生します。

この警告は、プログラムの予期せぬ動作を防ぐためのものなので、定数に新たな値を代入する必要がある場合は、その定数をfreezeするなどして、その定数の値が変わらないようにする必要があります。

○freezeしたオブジェクトの変更

freezeメソッドは、オブジェクト自体を変更不能にします。

しかし、そのオブジェクトが参照している他のオブジェクトまでは影響しません。

したがって、例えば配列やハッシュのような複合的なオブジェクトをfreezeした場合、そのオブジェクトの要素自体は変更可能なままです。

このような場合は、そのオブジェクトの各要素も同様にfreezeする必要があります。

これらの注意点を踏まえた上で、freezeメソッドをさらに活用する方法を見てみましょう。

●カスタマイズ方法

freezeメソッドと一緒に使うと便利なメソッドにdupメソッドがあります。

dupメソッドはオブジェクトを複製するメソッドで、freezeされたオブジェクトを複製して、その複製されたオブジェクトに対して変更を加えることができます。

○サンプルコード7:freezeとdupメソッドの組み合わせ

下記のコードは、freezeとdupメソッドを組み合わせて使っています。

# freezeとdupメソッドの組み合わせ
CONST = [1, 2, 3].freeze

dup_array = CONST.dup
dup_array[0] = 4  # => [4, 2, 3]

このコードでは、まず定数CONSTにfreezeした配列を代入しています。

その後でそのCONSTをdupメソッドで複製し、その複製した配列の最初の要素を4に変更しています。

この時点でエラーが発生することはありません、なぜならばdupによって複製されたオブジェクトは新たに作られたオブジェクトで、元のオブジェクトのfreezeの状態は引き継がれません。

したがって、dupによって複製されたオブジェクトは変更可能であり、このようにその要素を変更することができます。

以上が、Rubyの定数とfreezeメソッドの使い方についての解説です。

まとめ

Rubyの定数は、基本的には値の再代入が許されませんが、実際には警告を出すだけで、値の再代入自体は防げません。

しかし、freezeメソッドを使うと、オブジェクト自体の変更を防ぐことができ、定数が本当の意味で「定数」になります。

また、freezeメソッドは、イミュータブルなクラスを作成する際にも活用でき、そのクラスのインスタンスは作成後に変更されることがなく、プログラムの動作を安定させることができます。

しかし、freezeメソッドは、そのオブジェクトが参照している他のオブジェクトまでは凍結せず、freezeしたオブジェクトを変更しようとするとエラーが発生するという点に注意が必要です。

これらの点に注意しながら、freezeメソッドとdupメソッドを組み合わせて使うことで、オブジェクトの安全な操作を実現することができます。

以上、Rubyの定数とfreezeメソッドについての解説でした。

これらの知識をぜひあなたのコーディングに活用してください。