OpenStruct — это гибкая альтернатива Hash, которая предоставляет объектно-ориентированный интерфейс для работы с данными. Рассмотрим основные различия и случаи применения.
Hash:
person = { name: "John", age: 30 }
person[:name] # => "John"
person["name"] # => nil (ключ символ != строка)
OpenStruct:
require 'ostruct'
person = OpenStruct.new(name: "John", age: 30)
person.name # => "John"
person.age # => 30
person[:name] # NoMethodError
Hash требует явного присваивания:
person = {}
person[:name] = "John"
OpenStruct позволяет добавлять атрибуты через точку:
person = OpenStruct.new
person.name = "John"
person.age = 30
require 'benchmark'
data = { name: "John" }
os = OpenStruct.new(name: "John")
Benchmark.bm do |x|
x.report("Hash") { 1_000_000.times { data[:name] } }
x.report("OpenStruct") { 1_000_000.times { os.name } }
end
config = OpenStruct.new(
database: OpenStruct.new(
host: "localhost",
port: 5432
)
)
config.database.host # => "localhost"
user = OpenStruct.new(name: "John", role: "admin")
display_user_info(user)
Быстрое создание объектов без определения класса:
product = OpenStruct.new(
name: "Laptop",
price: 999.99,
specs: OpenStruct.new(
cpu: "i7",
ram: "16GB"
)
)
# Быстрый доступ к данным
cache = {}
cache[:user_123] = { name: "John" }
data = { a: 1, b: 2 }
data.transform_values { |v| v * 2 } # => { a: 2, b: 4 }
json_data = { user: { name: "John" } }.to_json
parsed = JSON.parse(json_data) # вернет Hash
Нет поддержки методов Hash:
each
, map
, select
и т.д.Нет вложенных операций:
os = OpenStruct.new(profile: { name: "John" })
os.profile[:name] # работает, но теряется смысл OpenStruct
Безопасность:
Struct:
Dry::Struct:
Классы данных (Data классы в Ruby 3.0+):
User = Data.define(:name, :age)
user = User.new("John", 30)
OpenStruct лучше использовать когда:
Hash предпочтительнее когда:
Помните: