When should I use Struct vs. OpenStruct?

后端 未结 9 1150
孤城傲影
孤城傲影 2020-11-28 00:35

In general, what are the advantages and disadvantages of using an OpenStruct as compared to a Struct? What type of general use-cases would fit each of these?

相关标签:
9条回答
  • 2020-11-28 01:14

    Have a look at the API with regard to the new method. A lot of the differences can be found there.

    Personally, I quite like OpenStruct, as I don't have to define the structure of the object beforehand, and just add stuff as I want. I guess that would be its main (dis)advantage?

    • http://www.ruby-doc.org/core/classes/Struct.html
    • http://www.ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html
    0 讨论(0)
  • 2020-11-28 01:17

    With an OpenStruct, you can arbitrarily create attributes. A Struct, on the other hand, must have its attributes defined when you create it. The choice of one over the other should be based primarily on whether you need to be able to add attributes later.

    The way to think about them is as the middle ground of the spectrum between Hashes on one side and classes on the other. They imply a more concrete relationship amongst the data than does a Hash, but they don't have the instance methods as would a class. A bunch of options for a function, for example, make sense in a hash; they're only loosely related. A name, email, and phone number needed by a function could be packaged together in a Struct or OpenStruct. If that name, email, and phone number needed methods to provide the name in both "First Last" and "Last, First" formats, then you should create a class to handle it.

    0 讨论(0)
  • 2020-11-28 01:17

    OpenStructs use significantly more memory and are slower performers versus Structs.

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

    On my system the following code executed in 14 seconds and consumed 1.5 GB of memory. Your mileage might vary:

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

    That finished nearly instantaneously and consumed 26.6 MB of memory.

    0 讨论(0)
  • 2020-11-28 01:18

    Using @Robert code, I add Hashie::Mash to the benchmark item and got this result:

                               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)
    
    0 讨论(0)
  • 2020-11-28 01:19

    The use cases for the two are quite different.

    You can think of the Struct class in Ruby 1.9 as an equivalent to the struct declaration in C. In Ruby Struct.new takes a set of field names as arguments and returns a new Class. Similarly, in C, a struct declaration takes a set of fields and allows the programmer to use the new complex type just like he would any built-in type.

    Ruby:

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

    C:

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

    The OpenStruct class can be compared to an anonymous struct declaration in C. It allows the programmer to create an instance of a complex type.

    Ruby:

    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;
    

    Here are some common use cases.

    OpenStructs can be used to easily convert hashes to one-off objects which respond to all the hash keys.

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

    Structs can be useful for shorthand class definitions.

    class MyClass < Struct.new(:a,:b,:c)
    end
    
    m = MyClass.new
    m.a = 1
    
    0 讨论(0)
  • 2020-11-28 01:22

    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
    
    0 讨论(0)
提交回复
热议问题