Create dynamic attribute in the Struct instance

老子叫甜甜 提交于 2021-02-20 10:12:23

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!