我有一个类应该看起来像这样:
class Family_Type1 @people = Array.new(3) @people[0] = Policeman.new('Peter', 0) @people[1] = Accountant.new('Paul', 0) @people[2] = Policeman.new('Mary', 0) def initialize(*ages) for i in 0 ... @people.length @people[i].age = ages[i] end end end
我希望能够在运行时定义一组类似于这一类的类(在启动时定义它们一次),其中数组的大小和分配给每个参数的类型是在运行时从外部规范文件定义的.
我有点使用evals工作,但这真的很难看.有更好的方法吗?
据我所知,你需要元编程.以下是使用初始化实例变量的初始化方法动态(动态)创建类的代码片段 -
class_name = 'foo'.capitalize klass = Object.const_set(class_name,Class.new) names = ['instance1', 'instance2'] # Array of instance vars klass.class_eval do attr_accessor *names define_method(:initialize) do |*values| names.each_with_index do |name,i| instance_variable_set("@"+name, values[i]) end end # more... end
希望你能调整它以满足你的要求.
首先,您的示例代码不适合您的部分原因是您有两个不同的@people
变量 - 一个是实例变量,另一个是类实例变量.
class Example # we're in the context of the Example class, so # instance variables used here belong to the actual class object, # not instances of that class self.class #=> Class self == Example #=> true @iv = "I'm a class instance variable" def initialize # within instance methods, we're in the context # of an _instance_ of the Example class, so # instance variables used here belong to that instance. self.class #=> Example self == Example #=> false @iv = "I'm an instance variable" end def iv # another instance method uses the context of the instance @iv #=> "I'm an instance variable" end def self.iv # a class method, uses the context of the class @iv #=> "I'm a class instance variable" end end
如果要在类中创建一次变量以在该类的实例方法中使用,请使用constants
或class variables
.
class Example # ruby constants start with a capital letter. Ruby prints warnings if you # try to assign a different object to an already-defined constant CONSTANT_VARIABLE = "i'm a constant" # though it's legit to modify the current object CONSTANT_VARIABLE.capitalize! CONSTANT_VARIABLE #=> "I'm a constant" # class variables start with a @@ @@class_variable = "I'm a class variable" def c_and_c [ @@class_variable, CONSTANT_VARIABLE ] #=> [ "I'm a class variable", "I'm a constant" ] end end
即便如此,在您的代码的上下文中,您可能不希望所有的Family_Type1实例都引用相同的警察和会计师吗?或者你呢?
如果我们切换到使用类变量:
class Family_Type1 # since we're initializing @@people one time, that means # all the Family_Type1 objects will share the same people @@people = [ Policeman.new('Peter', 0), Accountant.new('Paul', 0), Policeman.new('Mary', 0) ] def initialize(*ages) @@people.zip(ages).each { |person, age| person.age = age } end # just an accessor method def [](person_index) @@people[person_index] end end fam = Family_Type1.new( 12, 13, 14 ) fam[0].age == 12 #=> true # this can lead to unexpected side-effects fam2 = Family_Type1.new( 31, 32, 29 ) fam[0].age == 12 #=> false fam2[0].age == 31 #=> true fam[0].age == 31 #=> true
正如Chirantan所说,运行时初始化可以通过元编程完成,但是如果你只是初始化几个类,并且你知道他们的名字是什么,你也可以通过使用从文件中读取的任何内容来完成:
PARAMS = File.read('params.csv').split("\n").map { |line| line.split(',') } make_people = proc do |klasses, params| klasses.zip(params).map { |klass,name| klass.new(name, 0) } end class Example0 @@people = make_people([ Fireman, Accountant, Fireman ], PARAMS[0]) end class Example1 @@people = make_people([ Butcher, Baker, Candlestickmaker ], PARAMS[0]) end