🐘

Struct クラスの使い方

2023/12/24に公開

Struct クラスとは

構造体クラスと呼ばれる。
Struct.new をすることでサブクラスが作成される。

作成されたサブクラスでは、メンバ(プロパティ、フィールドとも言う)に対するアクセスメソッドが定義される。
https://docs.ruby-lang.org/ja/latest/class/Struct.html

使い方

環境はこちら

> ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin21]

第1引数が文字列のとき

第1引数がクラス名になる。
※クラス名なので大文字にすること。

Struct.new("User", :name, :age)
#=> Struct::User

user = Struct::User.new("名前", "年齢")

user.name
#=> "名前"
user.age
#=> "年齢"

第1引数がシンボルのとき

名前なしのクラスになる。
第1引数からメンバになる。

Struct.new(:name, :age)
=> #<Class:0x000000010c90e9c8>

# 名前を与えないときは clazz_〇〇という変数やメソッドに格納することが多い
clazz_user = Struct.new(:name, :age)
user = clazz_user.new("名前", "年齢")

user.name
#=> "名前"
user.age
#=> "年齢"

ブロックが渡されたとき

Struct.new("User", :name, :age) do
  def greeting
    puts "俺の名前は#{name}。"
    puts "年齢は#{age}歳さ。"
  end
end


user = Struct::User.new("ジョン", 20)

user.greeting
#=> 俺の名前はジョン。
#=> 年齢は20歳さ。

クラス定義との違い

同じことをする時に、initialize とか attr_reader の記述をしなくてもいい。

# クラス
class User
  attr_reader :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end
end

# struct
Struct.new("User", :name, :age)

あとは他のクラスを継承できない。

他のクラスへの継承はできるっぽい。

Struct.new("Patient", :name, :age)
class Child < Struct::Patient; end

child = Child.new("子供の名前", "子供の年齢")
child.name
#=> "子供の名前"

child.age
#=> "子供の年齢"

どういう時に使える??

最近現場のつよつよエンジニアが、 FormObject 内で attributes をセットしてるのをみて便利だと思った。

class OderForm
  attr_accessor :orders

  def initialize(params)
    @orders = assign_orders_attributes(params[:orders])
  end

  def save
    # 外部の API サーバーへ POST する処理。
  end

  private

    def assign_orders_attributes(attributes)
      attributes.map do |attribute|
        clazz_order.new(
          attribute[:name],
          attribute[:value]
        )
      end
    end

    def generate_api_params
      api_params = {}
      api_params[:orders] = []
      orders.each do |order|
        temp_hash = {}

        # Struct に格納されている各オーダーの情報をとりだして、リクエストパラメータを作っている
        temp_hash[:name] = order.name
        temp_hash[:value] = order.value

        api_params[:orders] << temp_hash
      end

      api_params
    end

    def clazz_order
      Struct.new(:name, :value)
    end
end

Discussion