Struct(構造体クラス)とは?
RubyにおけるStruct(構造体クラス)
は簡易的なクラスのようなもので、下記のようなケースで使用されます。
- まとまったデータを扱いたいが、クラスを作るまでもない場合。
- クラス内で特定のデータのまとまりを表現する場合。
通常のクラスとの違い
主に下記のような違いがあります。
- 継承、メンバの追加・削除ができない。
- 明示的にアクセスメソッドを定義しなくても、構造体クラス外でメンバの参照・更新が可能。
Struct(構造体クラス)の定義方法
定義方法(1)
第一引数にはString
で構造体クラス名
を渡します。(クラスと同じで大文字から始まる必要があります。)
第二引数以降にはSymbol
でメンバを渡します。
第一引数を渡した場合
Struct.new("User", :name, :age)
p Struct::User.new("Taro", 36) #=> #<struct Struct::User name="Taro", age=36>
第一引数を省略した場合
下記のように、第一引数を省略して定義する事も可能です。
User = Struct.new(:name, :age)
p User.new("Taro", 36) #=> #<struct User name="Taro", age=36>
定義方法(2)
Struct(構造体クラス)は下記のように定義する事も可能です。
class User < Struct.new(:name, :age)
end
p User.new("Taro", 36) #=> #<struct User name="Taro", age=36>
Struct(構造体クラス)インスタンスの作成
既に上記で確認できますが、クラスのようにnew
を使用する事で、Struct(構造体クラス)
のインスタンスを作成する事が可能です。
p User.new("Taro", 36) #=> #<struct User name="Taro", age=36>
指定数以上の引数を渡した場合
指定された数以上の引数を与えるとエラーになります。
User.new("Taro", 36, 4) #=> struct size differs
指定数に満たない数の引数を渡した場合
逆に、指定数に満たない数の引数を渡した場合は、値が渡されなかったメンバにnil
が入り、インスタンスが作成されます。
User = Struct.new(:name, :age)
User.new("Taro") #=> <struct User name="Taro", age=nil>
メンバの参照・更新方法
Struct(構造体クラス)
の定義時に指定したメンバは下記のように簡単に参照・更新する事が可能です。
user1 = User.new("Taro", 40)
# 参照
p user1.name #=> "Taro"
# 更新
user1.name = "Jiro"
p user1.name #=> "Jiro"
Struct(構造体クラス)にメソッドを定義する
クラスのように、do~end
のブロック内にインスタンスから呼べるメソッドを定義する事が可能です。
User = Struct.new("User", :name, :age) do
def intro
"私の名前は#{name}"
end
def say(word)
word
end
end
user1 = User.new("Taro",92)
p user1.intro #=> 私の名前はTaro
p user1.say("こんにちは") #=> こんにちは
また、通常のクラスのように、下記のようにする事でクラスから直接呼ぶメソッドの定義をする事も可能です。
User = Struct.new("User", :name, :age) do
class << self
def hoge
"Hoge"
end
end
def self.huga
"Huga"
end
end
p User.hoge #=> "Hoge"
p User.huga #=> "Huga"
Struct(構造体クラス)インスタンスの比較
Struct(構造体クラス)
の特徴の1つにインスタンスのメンバの値が同じであれば==
で比較した際にtrue
を返す事が挙げられます。
User = Struct.new(:name, :age)
user1 = User.new("Taro", 45)
user2 = User.new("Taro", 45)
user3 = User.new("Jiro", 90)
# メンバの値が同じなのでtrue
p user1 == user2 #=> true
# メンバの値が異なるのでfalse
p user1 == user3 #=> false
念の為ですが、クラスの場合は下記のようになります。
class User
def initialize(name, age)
@name = name
@age = age
end
end
user1 = User.new("Taro", 45)
user2 = User.new("Taro", 45)
# 異なるオブジェクトのためfalse
p user1 == user2 #=> false
Struct(構造体クラス)の実例
最後に、使い方のイメージが付くようStruct(構造体クラス)
の実例を紹介します。
冒頭で挙げた通り、Struct(構造体クラス)
は下記のように、クラス内で特定のデータのまとまりを表現する場合に使われます。
class User
Address = Struct.new(:city, :prefecture, :country)
def initialize(name, args)
@name = name
@address = Address.new(args[:city], args[:prefecture], args[:country])
end
end
user1 = User.new("Taro", { city: "Minato", prefecture: "Tokyo", country: "Japan"})
p user1 #=> <User:0x0000558567cc3408 @name="Taro", @address=#<struct User::Address city="Minato", prefecture="Tokyo", country="Japan">>