通常,与Struct相比,使用OpenStruct的优点和缺点是什么?哪种类型的一般用例适合其中的每一种?
通常,与Struct相比,使用OpenStruct的优点和缺点是什么?哪种类型的一般用例适合其中的每一种?
Answers:
使用OpenStruct
,您可以任意创建属性。Struct
另一方面,创建A时必须定义其属性。一个选择另一个应该主要基于您是否以后需要添加属性。
考虑它们的方法是,一方面是散列,另一方面是类之间的频谱的中间地带。它们暗示数据之间的关系比a更为具体Hash
,但它们没有实例方法,而类则没有。例如,函数的一堆选项在散列中有意义。它们只是松散相关。函数所需的名称,电子邮件和电话号码可以打包在Struct
或中OpenStruct
。如果该名称,电子邮件和电话号码需要使用“ First Last”和“ Last,First”两种格式提供名称的方法,则应创建一个类来处理它。
class Point < Struct.new(:x, :y); methods here; 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
先前:
为了完整性:Struct vs. Class vs. Hash vs. OpenStruct
在Ruby 1.9.2上运行与burtlo类似的代码((4个核中的1个x86_64,8GB RAM)[已编辑以对齐列的表]:
创建1个Mio结构: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倍 创建100K OpenStructs:10.96秒,369 MB / 242MB(virt / res)
OpenStructs是sloooooow和内存密集型,并没有为大型数据集的规模以及
创建1个神达OpenStructs是〜100倍慢于创造1个百万哈希值。
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
两者的用例完全不同。
您可以将Ruby 1.9中的Struct类视为等同struct
于C中的声明。在Ruby中,Ruby Struct.new
将一组字段名称作为参数并返回一个新的Class。同样,在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可用于轻松地将哈希转换为一次性对象,该对象可响应所有哈希键。
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
与Structs相比,OpenStructs使用大量内存,并且性能较慢。
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