我确信 Ruby 有一些方法可以让您动态定义常量,但我不会费心去查找它,因为这几乎 100% 感觉像是您不想做的事情。似乎您想要某种方式将“名称”与类实例相关联。这正是Hash 的用途。
people_names = ['John', 'Jane', 'Barbara', 'Bob']
people = people_names.each_with_object({}) do |name, ppl|
ppl[name] = Person.new(name)
end
people['John'].name # => 'John'
people['Jane'].name # => 'Jane'
为什么我说你要求的可能不是你想要的?因为在专业开发中通常不赞成使用元编程来动态创建和动态读取局部变量/常量/实例变量。对于您自己的项目,对于实验,当然可以。但是,对于作为团队一部分的任何项目,当您开始使用元编程功能来动态添加这些值并引用它们(可能是直接的,也可能是稍后间接引用)时,一切都很好,但是当您尝试弄清楚发生了什么时除非具有动态名称的数组是硬编码的,否则几乎永远无法弄清楚这些东西是从哪里定义/来自哪里的。如果它是硬编码的,为什么不能直接在代码中构建常量/变量/目标?这比动态执行要好得多。
# this is a fake API to demonstrate
# let's assume this is what you want
PEOPLE_NAMES = ['John', 'Jane']
PEOPLE_NAMES.each do |name|
const_def(name, Person.new)
end
get_person('Jane').do_something # maps to const_get('Jane').do_something
get_person(PEOPLE_NAMES[0]).do_something
John.do_something
如果你想要以上,你为什么不能这样做:
John = Person.new
Jane = Person.new
John.do_something
后者加载更清晰,仍然可以动态查找,但有一个硬编码的定义,可以在调试时轻松定位。
这是我的建议和回答。我很确定你不想做你要求做的事情。 Hash 完全符合您的需求,它被大量用于此类目的并与之密切相关,我建议您尝试使其满足您的需求,然后尝试找出如何解决您特别希望得到的问题也是一个答案。
编辑
作为一个非常有趣的插件,您可以在这里使用Hash 做一些非常酷的动态内容,除非您碰巧隐藏了哈希的来源,否则不会导致大量混乱。但你可以这样做:
people = Hash.new { |h, k| h[k] = Person.new(k) }
# right now, people contains no actual people
people['John'].name # => 'John'
# now people contains one Person instance
这很酷有两个原因 1)您不必有一个列表来生成散列,所以如果您在创建散列之后得到名称,那很好,您可以通过访问该用户名称来添加它们 2)懒惰,它只会使用你需要的内存。如果您使用所有四个人预加载哈希,然后仅从两个人访问数据,那么您浪费了未使用的 2 个 Person 实例所需的空间,所以这让您只使用所需的空间,否则为您提供所有相同的好处。