Structで簡易値オブジェクト
Ruby実践でのStructとOpenStruct
Rubyではデータ保持に便利な構造体が用意されています。Structはクラスを簡易定義でき、OpenStructは属性を動的に追加できる軽量クラスです。両者ともドットアクセスで値を取得・設定できるため、コードが読みやすくなります。
require 'ostruct'
# Structで簡易定義
User = Struct.new(:name, :email)
u = User.new('Alice', 'alice@example.com')
puts u.name # => Alice
# OpenStructで動的に属性を追加
profile = OpenStruct.new(name: 'Bob')
profile.age = 30
puts profile.age # => 30
Structはコンパイル時に固定された属性を持つため、パフォーマンスが若干優れます。一方、OpenStructは属性が自由に増減できるため、柔軟性が必要な場面で活躍します。
軽量クラスとしての構造体
構造体は値オブジェクトとして扱われることが多く、イミュータブルなデータを保持するのに適しています。RubyのStructは内部でStruct::newを呼び出すだけでクラスを生成できるため、軽量クラスとして即座に利用できます。
Point = Struct.new(:x, :y) do
def distance_from_origin
Math.sqrt(x**2 + y**2)
end
end
p = Point.new(3, 4)
puts p.distance_from_origin # => 5.0
このように、構造体はドットアクセスで属性にアクセスでき、メソッドを追加して機能を拡張することも可能です。値オブジェクトとして扱う場合は、freezeでイミュータブルにすることも推奨されます。
値オブジェクトとしての使い方
値オブジェクトは等価性を属性で判断し、変更不可であることが前提です。RubyのStructはデフォルトで==を属性比較に基づいて実装しているため、値オブジェクトとして即座に利用できます。
Address = Struct.new(:street, :city, :zip)
a1 = Address.new('1-1', 'Tokyo', '100-0001')
a2 = Address.new('1-1', 'Tokyo', '100-0001')
puts a1 == a2 # => true
さらに、freezeを呼び出すことでオブジェクトをイミュータブルにし、予期せぬ変更を防げます。
a1.freeze
# a1.street = '2-2' # => RuntimeError: can't modify frozen Address
このように、StructやOpenStructを活用することで、Ruby実践においてデータ保持と軽量クラスの設計を簡易定義で実現し、ドットアクセスで直感的に扱える値オブジェクトを作成できます。
コメント
コメントを投稿