配列ではなく、キーと値のペアで構成されているデータを扱うには、普通ハッシュを使うかと思います。
それ自体は間違いではありませんが、ハッシュにしてしまうとゲッターメソッドが使えず、オブジェクトかハッシュかを意識しながら扱わなくてはいけません。
要するに、クラスにするまでもない一時的なデータでもオブジェクトのようにゲッターメソッドを使いたいのです。
このような場合にはStructクラスを使うときれいに書くことができます。
Structクラス
例えば以下のようなハッシュを用意したとします。
user= {name: "jon", height: 175, weight: 70}
このデータから身長を取り出すには、
user[:height]
としなければなりません。
また、与えられたデータからBMIを計算する場合は以下のようになります。
user[:bmi] = user[:weight].to_f / ((user[:height] / 100) ** 2)
では、Structクラスを使ってみたいと思います。
UserData = Struct.new(:name, :height, :weight) user = UserData.new("jon", 175, 70) user.height bmi = user.weight.to_f / ((user.height / 100) ** 2)
見た目はオブジェクト指向らしくなりました。
ただ、残念なことにハッシュと異なり新しい属性を追加することはできません。
Structクラスは言わばクラスを作り出すクラスだと言えます。
これは例えではなく、今作ったUserDataはClassクラスのオブジェクトになっており、さらに、Structを親クラスに持ちます。
UserData.class #=> Class UserData,superclass #=> Struct
これは、以下のようにクラス定義したのと同じです。
class UserData < Struct attr_accessor :name, :height, :weight end
Structのありがたみ
- メソッド定義
Structによって作られたクラスはゲッターメソッドを提供してくれるほか、とても面白いことができます。
先ほどの例を少し改造します。
UserData = Struct.new(:name, :height, :weight) do def bmi weight.to_f / ((height / 100) ** 2) end end user = UserData.new("jon", 175, 70) bmi = user.bmi
なんと、メソッドの定義ができてしまうのです。
先ほど、新しい属性を追加することはできないと書きましたが、今回の例であればbmiメソッドの追加で対処することができました。
コードの中でメソッド定義が出てくるのはどうかと思うかもしれませんが、もともと構造化データを扱うためのものなので、もしいくつかのメソッドが欲しければクラス定義をしてしまえばいいのです。
- nil回避
ハッシュは存在しないキーについて参照しようとするとnilを返します。
user = {name: "jon", height: 175, weight: 70} user[:age] #=> nil
しかし、Structによって作られた構造化データは、存在しない属性にアクセスすると、通常のクラスと同じく例外を出してくれます。
UserData = Struct.new(:name, :height, :weight) user = UserData.new("jon", 175, 70) user.age #=> NoMethodError: undefined method `age'
参考
- 作者: Peter J. Jones,arton,長尾高弘
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/09
- メディア: 大型本
- この商品を含むブログ (13件) を見る
Ruby on Rails 5アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2017/04/14
- メディア: 大型本
- この商品を含むブログを見る
プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)
- 作者: 伊藤淳一
- 出版社/メーカー: 技術評論社
- 発売日: 2017/11/25
- メディア: 大型本
- この商品を含むブログを見る