LoginSignup
59
37

More than 1 year has passed since last update.

【Ruby】Struct(構造体クラス)を理解する

Last updated at Posted at 2020-03-31

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">>

参考

59
37
1

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
59
37