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

Rubyの変換メソッド完全ガイド!to_s・to_i・to_str・to_intの違いと使い分け方

整数を扱っているのに、gsubのような文字列用メソッドを使いたい——そんな場面に遭遇したことはありませんか?

どうすればいいのでしょうか?

答えはシンプルです。まずto_sで文字列に変換し、必要な処理を終えたらto_iで整数に戻します。

例えばInteger型の 1String型の "1" に変換できます。

変換後は新しいクラスのメソッドが使えるようになるため、それまで不可能だった操作が可能になります。

Rubyではすべてのオブジェクトが何らかのクラスに属し、各クラスには固有のメソッドセットが定義されていることを覚えておきましょう。

この記事で学べることは次のとおりです

  • Rubyで利用できる変換メソッドの種類
  • それぞれのメソッドの違い
  • 状況に応じた正しいメソッドの選び方

それでは見ていきましょう!

短い形式の変換メソッド(to_s、to_i、to_a)

最初に紹介するグループは、おそらくすでに馴染みのあるものばかりです。

例えば次のようなメソッドです

  • to_i
  • to_s
  • to_a

これらのメソッドは、現在のオブジェクトを表す特定クラスの新しいオブジェクトを返します。

例を見てみましょう

(1..10).to_a

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

このコードが意味するのは

Rangeオブジェクトである1..10を、その範囲を表すArrayに変換したい」

実はRubyには、これらの変換メソッドを暗黙的に呼び出してくれる仕組みもあります。

その代表例が文字列補間です:

"#{1}"

このコードでは、見た目上はわかりませんが、内部的に1.to_sが呼び出されています。

実際に確認したい方は、次のコードを実行してみてください

module Log
  def to_s
    puts "to_s called"
    super
  end
end

class Integer
  prepend Log
end

puts "#{1}"
# "to_s called"

注意:Ruby 2.3以前のバージョンでは、IntegerではなくFixnumを使う必要があります。可能であれば、Ruby自体を最新版にアップデートすることをおすすめします🙂

これらの短い形式の変換メソッドは非常に寛容な設計になっており、例外を発生させないのが基本です。

例えば

"aaaaaa".to_i

# 0

この 0 には驚くかもしれませんね。

しかし、数字を含まない文字列に対してto_iを呼び出すと、この結果になります。

記事の後半で紹介しますが、より厳格なバージョンのメソッドも存在します

長い形式の変換メソッド(to_str、to_int)

さて、ここで疑問が湧きます。

短い形式の変換メソッドがあるのに、なぜto_strto_intのようなメソッドが必要なのでしょうか?

違いは何でしょうか?

答えは「意図」の違いにあります。

Rubyのすべてのクラス(BasicObjectを除く)は、自身を何らかの文字列表現として返すto_sメソッドを実装しています。

しかし、文字列を返すからといって、そのオブジェクトが文字列のように振る舞うとは限りません!

具体例を見てみましょう

"" + 1
# TypeError: no implicit conversion of Fixnum into String

少し考えてみてください

空文字列に整数を足したら、何が返されるべきだと思いますか?

私にはわかりません。

"1"(数字の1を含む文字列)だと言う人もいるかもしれません。

でも、なぜそうなるのでしょう?

ほとんどの人にとって、これは直感に反する結果です。

そもそも足し合わせることに意味がない——だからこそTypeErrorが発生するのです。

仮にこれが許可されていたとしても…

こんなコードはどうでしょう

"" + {}

これは空文字列に空のハッシュを足しています。

やはり意味がありませんよね!

そこでRubyは、相手のオブジェクトが文字列「であるか」をチェックするのではなく(それはポリモーフィズムにとって好ましくありません)、文字列「のように振る舞うか」をチェックします。

ここで登場するのがto_strメソッドです。

Ruby 2.5でto_strを実装しているクラスはごくわずかです

  • String
  • NameError::message
  • Warning::buffer

独自の変換メソッドを実装する方法

任意のクラスにto_strを実装することができます。

そうすると、そのオブジェクトを文字列のように扱えるようになります。

例を挙げましょう

class Cat
  def to_str
    "meow"
  end
end

"" + Cat.new

# "meow"

ただし、そのクラスが文字列と同等と言える場合でなければ、この実装は避けるべきです

通常はto_sを使いましょう。

ちなみに、この仕組みは+メソッドだけのものではありません。

文字列ライクなオブジェクトのみが意味を持つ他の場面でも使われます。

例えば

[1,2,3].join(",")

to_intto_hashなど、他の長い形式の変換メソッドも同じロジックに従います。

だからこそ、Rubyにはこれらの異なるメソッドが存在するのです。

変換ラッパー(Conversion Wrappers)の使い方

まだ変換メソッドが物足りない方へ…ご安心ください。もういくつか紹介します!

私はこれらを「変換ラッパー」と呼んでいます。

具体的には次の3つです

  • Array()
  • Integer()
  • Hash[]

ちょっと変わった見た目のメソッドですよね!

丸括弧や角括弧に注目してください…

…これらの括弧こそが、メソッドとクラス名を区別する唯一の要素です。

これらの目的は何でしょうか?

Array()は、あらゆるオブジェクトを配列に変換します。

いくつか例を見てみましょう

Array(nil)
# []

Array([])
# []

Array(1)
# [1]

Array("")
# [""]

一体どんなロジックなのでしょうか???

実は、このメソッドには明確に定義されたルールがあります:

  • オブジェクトがto_aryまたはto_aに応答する場合、それを呼び出してその戻り値を返す
  • そうでない場合は、オブジェクトを空の配列に入れて返す

これで先ほどの挙動が説明できましたね。

この機能は、配列を期待するメソッドを書いているときに特に便利です。想定外のオブジェクトが渡されてアプリケーション全体がクラッシュするリスクがありますが、事前にArray()に通しておけば、確実に配列であることを保証できます。

続いてInteger()です。

こちらには特別なルールがあります

  • オブジェクトが文字列で、その内容がRubyの有効な数値表現に厳密に一致する場合はIntegerを返す。無効な形式の場合はArgumentErrorが発生する
  • オブジェクトが文字列でない場合は、まずto_int、次にto_iを呼び出そうとする
  • どの変換メソッドでも有効なIntegerに変換できない場合はTypeErrorが発生する

Integer(1)
# 1

Integer("25")
# 25

Integer("abc123")
# ArgumentError (invalid value for Integer(): "abc123")

Integer([])
# TypeError (can't convert Array into Integer)

このInteger()メソッドは、確実に有効なIntegerを扱いたい場合に非常に役立ちます。

最後にHash[]です。

偶数個の要素を持つ配列を渡すと、新しいハッシュが得られます:

Hash[[["a", 1], ["b", 2], ["c", 3]]]

# {"a"=>1, "b"=>2, "c"=>3}

2つの配列の要素をマージしてハッシュを作ったり、mapのようなメソッドと組み合わせたりする際に便利です。

まとめ

この記事では、Rubyのさまざまな変換メソッドについて、それらが存在する理由と実際の使い方を学びました!

短い形式(to_sto_i)は寛容な変換、長い形式(to_strto_int)は文字列や整数としての振る舞いを保証するためのもので、さらにArray()Integer()といった変換ラッパーを使えば、より厳格な型チェックも可能になります。状況に応じて適切なメソッドを選び、安全で読みやすいコードを書きましょう🙂

  1. RubyのStructとOpenStructの使い方を徹底解説!値オブジェクトを簡単に作る方法

    Rubyには、関連する属性をまとめて保持する「値オブジェクト」を手軽に作れるStructという組み込みクラスが用意されています。本記事では、Structの基本的な使い方から注意点、そしてOpenStructとの違いまで詳しく解説します。 そもそもStructとは何か? StructはRubyに組み込まれたクラスで、新しいクラスを動的に生成し、値オブジェクト(Value Object)を作成するために使われます。値オブジェクトとは、関連性のある複数の属性をひとまとめにして扱うためのオブジェクトです。 具体例を挙げてみましょう。 2つの座標(xとy)を持つPointというデータを表したい場合、この

  2. Rubyの配列(Array)クラスの使い方徹底解説!基本操作と便利なメソッド一覧

    配列(Array)とは? 配列はRubyに組み込まれたクラスで、0個以上の要素をリスト形式で保持することができます。さらに、要素の追加・アクセス・繰り返し処理を簡単に行えるメソッドも多数用意されています。 もし配列が存在しなければ、値ごとに個別の変数を用意しなければならず、管理が非常に大変になります。 例: a = 1 b = 2 c = 3 しかし、配列を使えば次のように書けます: numbers = [1, 2, 3] さらに嬉しいことに、配列の中には何でも入れられます! 例えば: 数値 文字列 さらに別の配列!(これは多次元配列になります) それでは、配列を最大限に活用できる