在 Ruby 中动态创建类 [英] Dynamically creating class in Ruby

查看:53
本文介绍了在 Ruby 中动态创建类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类应该是这样的:

I have a class that should look something like this:

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

我希望能够在运行时定义一堆与此类似的类(在启动时定义它们一次),其中数组的大小和分配给每个参数的类型是在运行时从外部规范文件定义的.

I want to be able to define a bunch of classes similar to this one at runtime (define them once at startup) where the size of the array and the type assigned to each parameter is defined at runtime from an external specification file.

我有点使用 eval 让它工作,但这真的很难看.有什么更好的方法吗?

I sort of got it to work using evals but this is really ugly. Any better way?

推荐答案

首先,您的示例代码不适合您的部分原因是您有两个不同的 @people 变量 -一个是实例变量,另一个是类实例变量.

First off, part of the reason your example code isn't working for you is that you have two different @people variables - one is an instance variable and the other is a class instance variable.

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

如果您想在一个类中一次性创建变量以在该类的实例方法中使用,请使用 constantsclass variables.

If you want to create variables one time in a class to use in instance methods of that class, use constants or 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 的所有实例都引用相同的警察和会计师,对吗?还是你?

Even so, in the context of your code, you probably don't want all your instances of Family_Type1 to refer to the same Policemen and Accountants right? Or do you?

如果我们切换到使用类变量:

If we switch to using class variables:

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 所说,运行时初始化可以通过元编程来完成,但是如果您只初始化几个类,并且知道它们的名称,那么您也可以使用从文件中读取的任何内容来完成:

The runtime initialization can be done with metaprogramming, as Chirantan said, but if you are only initializing a few classes, and you know what their name is, you can also do it just by using whatever you read from the file:

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

这篇关于在 Ruby 中动态创建类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆