一般的に、Structと比較してOpenStructを使用する利点と欠点は何ですか?どのタイプの一般的なユースケースがこれらのそれぞれに適合しますか?
OpenStruct
を使用すると、属性を任意に作成できます。一方、Struct
は、作成時に属性を定義する必要があります。どちらを選択するかは、主に後で属性を追加できるようにする必要があるかどうかに基づいて決定する必要があります。
それらについて考える方法は、一方のハッシュと他方のクラスとの間のスペクトルの中間点としてです。これらは、Hash
の場合よりもデータ間のより具体的な関係を意味しますが、クラスのようにインスタンスメソッドはありません。たとえば、関数の一連のオプションはハッシュで意味があります。それらは大まかに関連しているだけです。関数に必要な名前、電子メール、および電話番号は、Struct
またはOpenStruct
に一緒にパッケージ化できます。その名前、電子メール、および電話番号に、名前を「First Last」と「Last、First」の両方の形式で提供するメソッドが必要な場合、それを処理するクラスを作成する必要があります。
その他のベンチマーク:
require 'benchmark'
require 'ostruct'
REP = 100000
User = Struct.new(:name, :age)
USER = "User".freeze
AGE = 21
HASH = {:name => USER, :age => AGE}.freeze
Benchmark.bm 20 do |x|
x.report 'OpenStruct slow' do
REP.times do |index|
OpenStruct.new(:name => "User", :age => 21)
end
end
x.report 'OpenStruct fast' do
REP.times do |index|
OpenStruct.new(HASH)
end
end
x.report 'Struct slow' do
REP.times do |index|
User.new("User", 21)
end
end
x.report 'Struct fast' do
REP.times do |index|
User.new(USER, AGE)
end
end
end
ベンチマーク結果を自分で実行せずに把握したいせっかちな人向けに、上記のコードの出力を示します(MB Pro 2.4GHz i7で)
user system total real
OpenStruct slow 4.430000 0.250000 4.680000 ( 4.683851)
OpenStruct fast 4.380000 0.270000 4.650000 ( 4.649809)
Struct slow 0.090000 0.000000 0.090000 ( 0.094136)
Struct fast 0.080000 0.000000 0.080000 ( 0.078940)
UPDATE:
Ruby 2.4.1 OpenStructとStructの速度ははるかに近い。 https://stackoverflow.com/a/43987844/128421 を参照
以前:
完全を期すために:Structvs.Classvs.ハッシュvs.OpenStruct
Ruby 1.9.2、(4コアx86_64の1つ、8GB RAM)] [列を揃えるために編集されたテーブル]で、burtloのコードと同様のコードを実行します。
1 Mio Structsの作成:1.43秒、219 MB/90MB(virt/res) 1 Mioクラスインスタンスの作成:1.43秒、219 MB/90MB(virt/res) 1 Mioハッシュの作成:4.46秒、493 MB/364MB(virt/res) 1 Mio OpenStructsの作成:415.13秒、2464 MB/2.3GB(virt/res)#ハッシュ[.____。よりも100倍遅い。 ] 10万個のOpenStructsの作成:10.96秒、369 MB/242MB(virt/res)
OpenStructsは、sloooooowおよびメモリ集中型、および大規模なデータセットに対して適切にスケーリングしない
1つのMio OpenStructsを作成すると、〜100xが遅くなります1つのMioHashesを作成します。
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
2つのユースケースはまったく異なります。
Ruby 1.9のStructクラスは、Cのstruct
宣言と同等であると考えることができます。InRuby Struct.new
は、フィールド名のセットを引数として取り、新しいクラスを返します。同様に、Cでは、struct
宣言は一連のフィールドを受け取り、プログラマが組み込み型と同じように新しい複合型を使用できるようにします。
ルビー:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
OpenStructクラスは、Cの匿名のstruct宣言と比較できます。これにより、プログラマは、複合型のinstanceを作成できます。
ルビー:
o = OpenStruct.new(data1: 0, data2: 0)
o.data1 = 1
o.data2 = 2
C:
struct {
int data1;
char data2;
} o;
o.data1 = 1;
o.data2 = 2;
一般的な使用例を次に示します。
OpenStructsを使用すると、ハッシュをすべてのハッシュキーに応答する一時オブジェクトに簡単に変換できます。
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
構造体は、簡単なクラス定義に役立ちます。
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructsは大幅に多くのメモリを使用し、Structsよりもパフォーマンスが低下します。
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
私のシステムでは、次のコードが14秒で実行され、1.5 GBのメモリを消費しました。走行距離は異なる場合があります。
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
それはほぼ瞬時に終了し、26.6 MBのメモリを消費しました。
Struct
:
>> s = Struct.new(:a, :b).new(1, 2)
=> #<struct a=1, b=2>
>> s.a
=> 1
>> s.b
=> 2
>> s.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
OpenStruct
:
>> require 'ostruct'
=> true
>> os = OpenStruct.new(a: 1, b: 2)
=> #<OpenStruct a=1, b=2>
>> os.a
=> 1
>> os.b
=> 2
>> os.c
=> nil
新しいメソッドに関するAPIをご覧ください。そこには多くの違いがあります。
個人的には、オブジェクトの構造を事前に定義する必要がなく、必要に応じて追加するだけなので、OpenStructは非常に気に入っています。それが主な(不利な)利点になると思いますか?
@Robertコードを使用して、ベンチマーク項目にHashie :: Mashを追加し、次の結果を得ました。
user system total real
Hashie::Mash slow 3.600000 0.000000 3.600000 ( 3.755142)
Hashie::Mash fast 3.000000 0.000000 3.000000 ( 3.318067)
OpenStruct slow 11.200000 0.010000 11.210000 ( 12.095004)
OpenStruct fast 10.900000 0.000000 10.900000 ( 12.669553)
Struct slow 0.370000 0.000000 0.370000 ( 0.470550)
Struct fast 0.140000 0.000000 0.140000 ( 0.145161)