10
1

Rubyでキーワードによって処理を変えたい時、そのキーワードは文字列ではなくシンボルで表現しよう

Last updated at Posted at 2024-07-16

以下のように特定のキーワードによって処理を変えたいメソッドがあったとします。

# time_of_day(時間帯)によって適切な挨拶を返すメソッド
# time_of_dayの値は morning, night, daytime の3つ
# morningの場合はgood morning
# nightの場合はgoodbye
# daytimeの場合はhello を返す
#
def greeting(time_of_day)
  case time_of_day
  when 'morning'
    'Good morning'
  when 'night'
    'Goodbye'
  when 'daytime'
    'Hello'
  else
    'Invalid time of day'
  end
end

# メソッドのテスト
puts greeting('morning')  # => Good morning
puts greeting('night')    # => Goodbye
puts greeting('daytime')  # => Hello
puts greeting('evening')  # => Invalid time of day

このtime_of_dayの値によって処理を分けている所で、もし引数の値がアプリケーションの外からの入力値になるので文字列でないといけないなどの特別な理由が限り、文字列ではなくシンボルを使った方がいいよという話です。

def greeting(time_of_day)
  case time_of_day
  when :morning
    'Good morning'
  when :night
    'Goodbye'
  when :daytime
    'Hello'
  else
    nil
  end
end

# メソッドのテスト
puts greeting(:morning)  # => Good morning
puts greeting(:night)    # => Goodbye
puts greeting(:daytime)  # => Hello
puts greeting('evening')  # => nil

理由は単純で、文字列としての機能が必要ないのであれば、シンボルの方が効率的だからです。

シンボル(Symbol)は同じ値は同じオブジェクト、文字列は違うオブジェクト

Helloという同じ値の文字列と同じ値のシンボルのobject_idを確認した場合のキャプチャが以下になります。

image.png

このように'Hello'は実行するたびにobject_idが違う、つまり違うオブジェクトを毎回生成しているということですが、:Helloは同じobject_idなので、一度作ったものを再度使い回していることがわかります。
このコードがプロセスを立ち上げた後に100万回実行されたら100万個分のメモリが必要になるか、一個で済むかでメモリ使用量は大きく変わってしまいます。

オブジェクトで利用するメモリ量もシンボルの方が格段に少ない

ObjectSpaceというモジュールを使うとそのオブジェクトで利用しているメモリサイズがわかるので、それを使って文字列とシンボルのメモリサイズを比較してみます。

image.png

memsize_ofというメソッドは引数で与えられたオブジェクトのメモリサイズをByteの整数(Integer)で返すメソッドです。

同じことを表現している文字列とシンボルでもメモリ使用量が大きく違いますし、文字数が増えると文字列の場合はそれに合わせてメモリ利用量も増えますが、シンボルは変わりません。

これはシンボルが内部的には数値と同じ扱いになっているためかなり軽量になっているようです

image.png

まとめ

このようにシンボルと文字列はメモリ使用量において大きな差があり、シンボルで事足りる場合はシンボルを使った方が効率的になります。

正直シンボルでもいいところを文字列にしたところで、バグは出ないだろうしGCも発達しているのでこれが原因でアプリケーションに問題が出るようなことはほぼないと思います。

しかしアプリケーションを運用していてメモリ使用量が大きくなってきたときにコードを精査してこの修正を加えていくのはかなり面倒臭いので、息を吸うように使い分けできるようになるのがいいかなーと思います。

一緒にCBcloudで働いてくれる人募集!!!

私は現在CBcloudという、新しい配送インフラを作っていくことを目指す会社に所属して、日々Rubyでその配送インフラの実現のためにコードを書いています。

この記事は業務時間中に書いているので、それはつまり Sponsered by CBcloud のようなものなので宣伝です!

CBcloudで、一緒にRubyで新しい配送インフラを作ってくれる人を募集しているのでご興味のある方はぜひ採用サイトを覗いてみてください!

沖縄オフィスもありまして、沖縄オフィス用の採用サイトもあるのでそちらも是非是非!

10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1