【Ruby】値渡しの基本から応用まで10ステップ

Rubyの値渡しを解説する記事のサムネイルRuby
この記事は約9分で読めます。

 

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

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

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

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

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

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

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

はじめに

プログラミングにおける重要な概念として、「値渡し」があります。

初心者の方々にとっては少々難しいと感じるかもしれませんが、しっかりと理解していけば、より効率的なコーディングが可能になります。

この記事では、Rubyにおける値渡しの基本から応用までを、10のステップで解説します。

手を動かしながら学べるサンプルコードも豊富に揃えていますので、ぜひ最後までご覧ください。

●Rubyとは

Rubyは、まつもとゆきひろ氏によって開発されたプログラミング言語の一つです。

シンプルで直感的な構文が特徴で、初心者にも学びやすい言語として人気があります。

●値渡しとは

プログラミングにおいて、データの扱い方は非常に重要です。

特に関数やメソッドに値を渡す方法は、プログラムの動作とメモリの管理に大きく影響を与えます。

ここでは、その中でも「値渡し」という基本的なデータの渡し方に焦点を当て、そのメカニズムと利点について掘り下げます。

値渡しの概念を理解することは、プログラミング初心者にとっても重要な一歩となり、コードの予測可能性と安全性の向上に繋がります。

○値渡しの基本

値渡しとは、ある変数から別の変数に値を「コピー」して渡す方法のことを指します。

この際、元の変数がどのような変更を受けても、コピーした値(新しい変数)には影響がありません。

これは、変数が指す「値そのもの」がコピーされるからです。

●Rubyにおける値渡しの動作

ここでは、具体的なサンプルコードを通じてRubyにおける値渡しの基本動作を解説し、その特性を見ていきます。

○サンプルコード1:値渡しの基本動作

Rubyでは、値渡しは次のように動作します。

このサンプルコードでは、数字の5を代入した変数aを別の変数bにコピーしています。

その後、aの値を変更しても、bの値には影響がないことが確認できます。

a = 5
b = a  # aの値をbにコピー
a = 3  # aの値を変更

puts a  # => 3
puts b  # => 5

この例では、変数aの値を変更しても、変数bの値は変わらないという値渡しの特性を確認できます。

○サンプルコード2:オブジェクトの変更と値渡し

しかし、Rubyでは、オブジェクト自体を変更する操作が行われると、結果は少し異なります。

このサンプルコードでは、配列を値渡しして、その後で元の配列を変更してみます。

a = [1, 2, 3]
b = a
a << 4  # aの配列に新しい要素を追加



puts a  # => [1, 2, 3, 4]
puts b  # => [1, 2, 3, 4]

この例では、配列aに新しい要素を追加したとき、値渡しした配列bも同じ変更が反映されました。

これは、Rubyにおけるオブジェクトの参照の仕組みから生じる現象で、値渡しには注意が必要です。

次の章では、この問題に対処するための応用例を紹介します。

●値渡しの応用例

Rubyにおける値渡しの基本を理解したところで、次はその応用例を見てみましょう。

○サンプルコード3:値渡しを活用した関数の作成

このコードでは、関数内での値渡しの利用を示しています。

関数doubleは引数として渡された数字を2倍にして返すというものです。

def double(n)
  n *= 2  # nの値を2倍にする
  return n
end

a = 5
b = double(a)

puts a  # => 5
puts b  # => 10

この例では、double関数に変数aを渡すと、関数内で2倍にされた値が返され、新しい変数bに代入されます。

関数内での計算によりaの値が変更されるわけではないため、値渡しの特性を活かした処理になっています。

○サンプルコード4:値渡しと参照渡しの違い

次の例は、Rubyにおける値渡しと参照渡しの違いを明示的に表すものです。

def modify_str(s)
  s += " World!"  # 文字列sに" World!"を追加
end

def modify_arr(a)
  a << " World!"  # 配列aに新しい要素を追加
end

str = "Hello"
arr = ["Hello"]

modify_str(str)
modify_arr(arr)

puts str  # => "Hello"
puts arr  # => ["Hello", " World!"]

ここでは、文字列と配列、2つの異なるデータ型を操作しています。

Rubyでは文字列は値渡しで、配列は参照渡しの性質を持っています。

したがって、関数内で文字列を操作しても元の文字列には影響がありませんが、配列を操作すると元の配列に影響が出ることがわかります。

○サンプルコード5:配列と値渡し

配列を値渡しする際の注意点を示すためのコードです。

配列には参照渡しの性質がありますので、注意が必要です。

def add_element(arr)
  arr << "New element"
end

original = ["Element1", "Element2"]
copied = original.dup  # 配列をコピー

add_element(original)

puts original  # => ["Element1", "Element2", "New element"]
puts copied  # => ["Element1", "Element2"]

このコードでは、元の配列に新しい要素を追加しています。

しかし、dupメソッドを使って作成したコピーは元の配列の変更から影響を受けません。

これは、dupメソッドが配列のシャローコピーを作成するためです。

したがって、オブジェクトの状態を維持する場合には、このようにコピーを作成することが重要です。

○サンプルコード6:ハッシュと値渡し

ハッシュもまた、配列同様に参照渡しの性質を持つデータ型です。

したがって、値渡しによるハッシュの操作は、配列と同じように注意が必要です。

def change_value(h)
  h[:key1] = "Changed!"
end

hash = {key1: "Original", key2: "Original"}
copied_hash = hash.dup

change_value(hash)

puts hash  # => {:key1=>"Changed!", :key2=>"Original"}
puts copied_hash  # => {:key1=>"Original", :key2=>"Original"}

ここでは、元のハッシュの値を変更しています。

しかし、dupメソッドを使って作成したハッシュのコピーは元のハッシュの変更から影響を受けません。

これは、dupメソッドがハッシュのシャローコピーを作成するためです。

したがって、ハッシュの状態を維持する場合には、このようにコピーを作成することが重要です。

●値渡しにおける注意点

値渡しは強力なツールである一方で、間違った使用方法は思わぬバグを引き起こす可能性があります。

注意しなければならないのは、特にRubyの配列やハッシュなど、参照渡しの性質を持つオブジェクトに対する操作です。

これらのオブジェクトに対して直接操作を行うと、元のオブジェクトまで影響を及ぼしてしまうことがあるため、コピーを作成するなどの配慮が必要です。

○サンプルコード7:注意点を考慮したコード例

このコードでは、配列のコピーを作成し、それを操作することで元の配列を安全に保護する方法を表しています。

def manipulate_array(arr)
  arr_copy = arr.dup
  arr_copy << "New element"
  return arr_copy
end

original = ["Element1", "Element2"]
manipulated = manipulate_array(original)

puts original  # => ["Element1", "Element2"]
puts manipulated  # => ["Element1", "Element2", "New element"]

この例では、関数manipulate_arrayの中で配列のコピーを作成しています。

そのため、元の配列originalに影響を及ぼすことなく新しい要素を追加することが可能になります。

このように、値渡しを行う際には元のオブジェクトに影響を及ぼさないように注意が必要です。

●値渡しのカスタマイズ方法

Rubyでは、オブジェクトの状態を保護するためのメソッドが提供されています。

これらを活用することで、値渡しの処理をより安全に、またはカスタマイズした形で行うことが可能です。

○サンプルコード8:カスタマイズ例

このコードでは、配列を冷凍することで、それに対する変更を防ぐfreezeメソッドの使用例を表しています。

def try_to_change_array(arr)
  begin
    arr << "New element"
  rescue => e
    puts e.message
  end
end

arr = ["Element1", "Element2"]
arr.freeze  # 配列を冷凍する

try_to_change_array(arr)

この例では、配列arrをfreezeメソッドによって冷凍しています。

そのため、新しい要素の追加など、配列に対する変更を試みるとエラーが発生します。

これにより、配列の状態が安全に保護されます。

このようなRubyの機能を活用することで、値渡しの処理をより安全に、またはカスタマイズした形で行うことが可能になります。

まとめ

Rubyにおける値渡しの基本から応用まで、私たちは10のステップを通じてその使い方を解説しました。

特に重要なのは、値渡しはオブジェクトのコピーを作成し、それを操作することで元のオブジェクトを保護することができるという点です。

配列やハッシュなどのオブジェクトに対する操作には特に注意が必要で、Rubyの配列のdupメソッドやfreezeメソッドなどの機能を活用することで、これらの問題を回避することが可能です。

これらのテクニックをマスターすることで、より効率的でバグの少ないコードを書くことができるでしょう。

この記事が、Rubyでの値渡しについて理解を深める一助になれば幸いです。