一般的に、Structと比較してOpenStructを使用する利点と欠点は何ですか?これらのそれぞれに適合するのは、どのような一般的なユースケースですか?
一般的に、Structと比較してOpenStructを使用する利点と欠点は何ですか?これらのそれぞれに適合するのは、どのような一般的なユースケースですか?
回答:
を使用するとOpenStruct
、任意に属性を作成できます。Struct
一方、Aは、作成時に属性を定義する必要があります。どちらを選択するかは、後で属性を追加できるようにする必要があるかどうかに主に基づいて決定する必要があります。
それらについて考える方法は、一方のハッシュともう一方のクラスの間のスペクトルの中間点としてです。これらは、の場合よりもデータ間のより具体的な関係を意味Hash
しますが、クラスのようにインスタンスメソッドはありません。たとえば、関数のオプションの束はハッシュで意味をなします。それらは大まかに関連しています。関数に必要な名前、電子メール、および電話番号は、Struct
またはにまとめてパッケージ化できますOpenStruct
。その名前、電子メール、および電話番号で、「First Last」と「Last、First」の両方の形式で名前を提供するメソッドが必要な場合は、それを処理するクラスを作成する必要があります。
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
です。(ソース)もちろん、 { ... }
複数行のブロック(do ... end
)として記述することもできますが、それが望ましい方法だと思います。
その他のベンチマーク:
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)
更新:
Ruby 2.4.1の時点で、OpenStructとStructの方がはるかに高速です。https://stackoverflow.com/a/43987844/128421を参照してください
以前:
完全性のために:構造体 vs クラス vs ハッシュ vs OpenStruct
Ruby 1.9.2でburtloと同様のコードを実行(4コアのうちの1つx86_64、8 GB RAM)[列を整列するために編集されたテーブル]:
1 Mio Structsの作成:1.43秒、219 MB / 90MB(virt / res) 1 Mioクラスインスタンスの作成:1.43秒、219 MB / 90 MB(仮想/解像度) 1 Mioハッシュの作成:4.46秒、493 MB / 364MB(仮想/解像度) 1 Mio OpenStructsの作成:415.13秒、2,464 MB / 2.3GB(virt / res)#ハッシュより〜100倍遅い 100K OpenStructsの作成:10.96秒、369 MB / 242MB(virt / res)
OpenStructsはありsloooooowとメモリ集約、および大規模なデータセットのためにうまく拡張しないでください
1 Mio OpenStructsの作成は、1 Mio ハッシュの作成よりも〜100倍遅くなります。
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クラスはstruct
、C の宣言に相当すると考えることができます。Ruby Struct.new
では、引数としてフィールド名のセットを取り、新しいクラスを返します。同様に、Cでは、struct
宣言は一連のフィールドを取り、プログラマーが組み込み型と同じように新しい複合型を使用できるようにします。
ルビー:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
OpenStructクラスは、Cの匿名構造体宣言と比較できます。これにより、プログラマーは複合型のインスタンスを作成できます。
ルビー:
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を使用すると、ハッシュを、すべてのハッシュキーに応答する1回限りのオブジェクトに簡単に変換できます。
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)
実際には質問に対する回答ではありませんが、パフォーマンスを重視する場合は非常に重要な考慮事項です。OpenStruct
操作を作成するたびにメソッドキャッシュがクリアされることに注意してください。これは、アプリケーションのパフォーマンスが低下することを意味します。遅いかOpenStruct
どうかは、それ自体がどのように機能するかだけでなく、それらを使用することがアプリケーション全体にもたらす影響です:https : //github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md#openstructs