rails example ruby struct

rails - ruby struct example



¿Cuándo debería usar Struct vs. OpenStruct? (8)

Eche un vistazo a la API con respecto al nuevo método. Muchas de las diferencias se pueden encontrar allí.

Personalmente, me gusta bastante OpenStruct, ya que no tengo que definir la estructura del objeto de antemano, y simplemente agregar cosas como quiero. Supongo que esa sería su principal (des) ventaja?

En general, ¿cuáles son las ventajas y desventajas de usar un OpenStruct en comparación con un Struct? ¿Qué tipo de casos de uso generales encajarían en cada uno de estos?


Las OpenStructs usan mucha más memoria y son más lentas en comparación con Structs.

require ''ostruct'' collection = (1..100000).collect do |index| OpenStruct.new(:name => "User", :age => 21) end

En mi sistema, el siguiente código se ejecutó en 14 segundos y consumió 1,5 GB de memoria. Su millaje puede variar:

User = Struct.new(:name, :age) collection = (1..100000).collect do |index| User.new("User",21) end

Eso terminó casi instantáneamente y consumió 26.6 MB de memoria.


Los casos de uso para los dos son bastante diferentes.

Puedes pensar en la clase Struct en Ruby 1.9 como equivalente a la declaración struct en C. En Ruby Struct.new toma un conjunto de nombres de campo como argumentos y devuelve una nueva clase. De forma similar, en C, una declaración de struct toma un conjunto de campos y le permite al programador usar el nuevo tipo complejo tal como lo haría con cualquier tipo incorporado.

Rubí:

Newtype = Struct.new(:data1, :data2) n = Newtype.new

DO:

typedef struct { int data1; char data2; } newtype; newtype n;

La clase OpenStruct se puede comparar con una declaración de estructura anónima en C. Permite al programador crear una instancia de un tipo complejo.

Rubí:

o = OpenStruct.new(data1: 0, data2: 0) o.data1 = 1 o.data2 = 2

DO:

struct { int data1; char data2; } o; o.data1 = 1; o.data2 = 2;

Aquí hay algunos casos de uso común.

OpenStructs se puede usar para convertir fácilmente hashes en objetos únicos que responden a todas las claves hash.

h = { a: 1, b: 2 } o = OpenStruct.new(h) o.a = 1 o.b = 2

Las estructuras pueden ser útiles para definiciones de clase taquigráficas.

class MyClass < Struct.new(:a,:b,:c) end m = MyClass.new m.a = 1


Otro punto de referencia:

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

Para los impacientes que quieran hacerse una idea de los resultados de referencia, sin ejecutarlos ellos mismos, aquí está el resultado del código anterior (en un 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)


Utilizando el código @Robert, agrego Hashie :: Mash al elemento de referencia y obtuve este resultado:

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)


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


ACTUALIZAR:

A partir de Ruby 2.4.1, OpenStruct y Struct están mucho más cerca en velocidad. Ver https://.com/a/43987844/128421

PREVIAMENTE:

Para completar: Struct vs. Class vs. Hash vs. OpenStruct

Ejecutando código similar al de burtlo, en Ruby 1.9.2, (1 de 4 núcleos x86_64, 8GB RAM) [tabla editada para alinear columnas]:

creating 1 Mio Structs : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Class instances : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Hashes : 4.46 sec , 493 MB / 364MB (virt/res) creating 1 Mio OpenStructs : 415.13 sec , 2464 MB / 2.3GB (virt/res) # ~100x slower than Hashes creating 100K OpenStructs : 10.96 sec , 369 MB / 242MB (virt/res)

Las OpenStructs son poco frecuentes y requieren mucha memoria , y no se adaptan bien a grandes conjuntos de datos

Crear 1 Mio OpenStructs es ~ 100x más lento que crear 1 Mio Hashes .

start = Time.now collection = (1..10**6).collect do |i| {:name => "User" , :age => 21} end; 1 stop = Time.now puts "#{stop - start} seconds elapsed"


Con OpenStruct , puede crear atributos arbitrariamente. Un Struct , por otro lado, debe tener sus atributos definidos cuando lo crea. La elección de uno sobre el otro debe basarse principalmente en si necesita poder agregar atributos más tarde.

La manera de pensar sobre ellos es como el término medio del espectro entre Hashes por un lado y las clases por el otro. Implican una relación más concreta entre los datos que un Hash , pero no tienen los métodos de instancia como una clase. Un montón de opciones para una función, por ejemplo, tiene sentido en un hash; solo están vagamente relacionados. El nombre, el correo electrónico y el número de teléfono que necesita una función se pueden empaquetar juntos en un Struct o OpenStruct . Si ese nombre, correo electrónico y número de teléfono necesitan métodos para proporcionar el nombre en los formatos "Primero el último" y "Último, primero", entonces debe crear una clase para manejarlo.