问题
Is it possible to create attribute dynamicaly in the Struct
instance?
class Person < Struct.new(:name)
end
p = Person.new("Bilbo")
p[:surname] = "Jenkins" # does not work
回答1:
You could use an OpenStruct
:
require 'ostruct'
p = OpenStruct.new(name: "Bilbo")
p[:surname] = "Jenkins"
p.surname # => "Jenkins"
回答2:
You can define new methods on your Person
class by doing this:
Person.send(:define_method, :surname){@surname}
Person.send(:define_method, :surname=){|x|@surname=x}
I prefer define_method
instead of instance_eval
because I try to omit eval
when possible.
回答3:
You can subclass Struct
, in which case you will be creating two classes, but it is more common to just create one:
Person = Struct.new(:name)
Person.instance_methods(false)
#=> [:name, :name=]
p = Person.new("Bilbo")
#=> #<struct Person name="Bilbo">
Does `p` have an instance variable `@name` whose value is `"Bilbo"`?
p.instance_variables
#=> []
No, it does not. Rather, it has "members":
p.members
#=> [:name]
Can name
be treated as an instance variable with the accessors provided by Struct
?
p.name
#=> "Bilbo"
p.name = "cat"
p.name
#=> "cat"
Yes! That's because the members of a Struct
instance are stored in array that you are not intended to access directly, only through the accessors.
Can we add Struct
members dynamically? I don't know the answer to that, but methods are not provide to do that easily. Instead, just add instance variables and, optionally, accessors.
We can add an instance variable and set its value with:
p.instance_variable_set('@surname', 'Jenkins')
#=> "Jenkins"
p.instance_variables
#=> [:@surname]
and retrieve its value with:
p.instance_variable_get('@surname')
#=> "Jenkins"
If you wish to create accessors for that variable, this is one way:
p.class.instance_eval do
attr_accessor :surname
end
p.surname
#=> "Jenkins"
p.surname = 'cat'
#=> "cat"
p.surname
#=> "cat"
p.class.instance_methods(false)
#=> [:name, :name=, :surname, :surname=]
来源:https://stackoverflow.com/questions/27700226/create-dynamic-attribute-in-the-struct-instance