动态地向Ruby对象添加属性

Nik*_*arg 41 ruby

我创建了一个对象,我想基于一些条件检查,为这个对象添加一些属性.我怎样才能做到这一点?解释我想要的东西:

A=Object.new
if(something happens)
{
  #make A have another attibute say age
  #& store something in A.age

}
Run Code Online (Sandbox Code Playgroud)

jig*_*fox 48

首先,关于ruby的事情是它允许一种不同的语法,这种语法被ruby编码器广泛使用.大写的标识符是类或常量(感谢sepp2k的评论),但你试图使它成为一个对象.并且几乎没有人使用{}do标记多行块.

a = Object.new
if (something happens)
  # do something
end
Run Code Online (Sandbox Code Playgroud)

我不确定你的问题是什么,但我有一个想法,这将是解决方案:

如果您知道该类可以具有哪些属性,并且它应该使用它是有限的

class YourClass
  attr_accessor :age
end
Run Code Online (Sandbox Code Playgroud)

attr_accessor :age 是短的:

def age
  @age
end
def age=(new_age)
  @age = new_age
end
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

a = YourClass.new
if (some condition)
  a.age = new_value
end
Run Code Online (Sandbox Code Playgroud)

如果你想完全动态地做,你可以做这样的事情:

a = Object.new
if (some condition)
  a.class.module_eval { attr_accessor :age}
  a.age = new_age_value
end
Run Code Online (Sandbox Code Playgroud)

  • @Nikhil:实际上它*是*语法,而不是常规问题.任何以大写字母开头的标识符都是ruby中的常量.所以`a = Object.new`和`A = Object.new`做的事情太不相同了(第一个定义了一个局部变量,另一个定义了一个全局常量). (8认同)
  • 但这会使该类的所有实例都具有此属性,而不仅仅是对象 (2认同)

use*_*008 21

这会将属性仅添加到对象:

a = Object.new
if (something happens)
  class << a
    attr_accessor :age
  end
  a.age = new_age_value
end
Run Code Online (Sandbox Code Playgroud)


Dav*_*son 20

您可以使用OpenStruct:

a = OpenStruct.new
if condition
    a.age = 4
end
Run Code Online (Sandbox Code Playgroud)

或者只使用普通的旧哈希.


Jon*_*nas 11

如果在代码编写时知道属性的名称,那么您可以执行已建议的内容:

class A
end

a = A.new
a.age = 20 # Raises undefined method `age='

# Inject attribute accessors into instance of A
class << a
  attr_accessor :age
end

a.age = 20 # Succeeds
a.age # Returns 20

b = A.new
b.age # Raises undefined method, as expected, since we only modified one instance of A
Run Code Online (Sandbox Code Playgroud)

但是,如果属性的名称是动态的并且仅在运行时已知,那么您将不得不以attr_accessor不同的方式调用:

attr_name = 'foo'

class A
end

a = A.new
a.foo = 20 # Raises undefined method `foo='

# Inject attribute accessors into instance of A
a.instance_eval { class << self; self end }.send(:attr_accessor, attr_name)

a.foo = 20 # Succeeds
a.foo # Returns 20
Run Code Online (Sandbox Code Playgroud)

  • 你也可以做`a.singleton_class.send(:attr_accessor,attr_name)`.谢谢! (6认同)

Dan*_*man 6

您可以使用instance_variable_set在Object类的实例上设置变量(并instance_variable_get获取它.)Object类没有可以直接设置的任何属性.

但是,我怀疑这不是你想要实现的目标的最佳解决方案; 它不是直接使用Object类的规范,而是定义或使用从中继承的类,它们具有您想要使用的属性.