Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 使用由字符串定义的名称初始化实例_Ruby - Fatal编程技术网

Ruby 使用由字符串定义的名称初始化实例

Ruby 使用由字符串定义的名称初始化实例,ruby,Ruby,在“纯ruby”(非rails)中,给定一个类: class Person end …和字符串数组: people_names = ['John', 'Jane', 'Barbara', 'Bob'] 如何实例化Person类,并将每个实例变量命名为数组中的一个元素 John = Person.new Jane = Person.new Barbara = Person.new Bob = Person.new 我相信Ruby有一些方法可以让你动态地定义常量,但我不想费心去查找,因为这感觉

在“纯ruby”(非rails)中,给定一个类:

class Person
end
…和字符串数组:

people_names = ['John', 'Jane', 'Barbara', 'Bob']
如何实例化
Person
类,并将每个实例变量命名为数组中的一个元素

John = Person.new
Jane = Person.new
Barbara = Person.new
Bob = Person.new

我相信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
实例所需的空间,因此,这让您只使用您所需要的,否则会提供所有相同的好处。

由于ruby中以大写字母开头的标识符是一个常量,因此不清楚您真正想要的是什么

John = Person.new
Jane = Person.new
Barbara = Person.new
Bob = Person.new
您可以使用动态分配常量


你当然可以做到,尽管正如布兰登所说,这可能不是一个好主意。以下是如何做到这一点:

people_names.each { |name| eval("#{name} = Person.new")}
eval
接受作为参数传递的字符串,并将其作为代码行执行。因此,您可以使用
each
为数组的每个成员执行一次

你可能想在谷歌上搜索“eval”来查看任何数量的关于为什么它是邪恶的文章。一般来说,其中很多都是元编程(
eval
是元编程的一个例子),并提出了一些好的观点。我有一种更温和的元编程方法(
attr\u accessor
,毕竟,也是元编程的一个例子,人们一直都在使用它),但您当然可以使用
eval
编写一些非常复杂的代码


另外请注意,正如一些海报所观察到的,通过大写字符串,您将它们定义为常量。您可以在Ruby中更改常量的值,但每次更改时都会收到警告。

值得一提的是,使用大写字母作为变量名会使它们成为常量。不确定这是否就是你的目标,dup目标是关于局部变量的。这个问题实际上是关于常数的-它的措辞非常糟糕。除了示例代码之外,我看不到任何迹象表明这个问题是关于常数的,从来没有明确指出它们是常量,我假设作者可能不知道Ruby中的变量是常量,如果第一个字母是大写。他还询问了实例变量,但没有@sigil。事实上我不知道该怎么办@BrandonBuckYea这是我的观点,确实没有足够的信息来确定他想要什么。作为一个插件,您使用的哈希变量可以是常量/实例变量/局部变量,基本上分配给您想要的任何类型的变量。它可以传递给函数、复制等。。。它比一些定义动态数据的范围局部方法更通用。呃,Rails使用了大量的动态实例/常量赋值。但我想这是所谓的专业开发人员所不赞成的。eval实际上不会定义新的局部变量<代码>评估('John=Person.new');约翰工作。但是
eval('john=Person.new');john
给出了一个名称错误。@max确实如此。这是个坏主意。:)实际上,它将定义新的局部变量,不过:
eval(“a=7”)
也可以工作。似乎它只是不允许您定义类实例?不,我很确定它不会声明新的实例变量。我猜你已经声明了
a
。这在文档中得到了解释,在这方面,它的工作原理与eval完全相同。我个人认为它是错误的,因为语言允许重新分配常量。如果一个“常数”不是,你知道,常数有什么意义?我可以使用类似于
const_set
的方法来支持常量的重新分配(带有警告),但我认为本机硬编码的重新分配应该是一个错误。@max
['John', 'Jane', 'Barbara', 'Bob'].map(&:downcase).each do |name|
  instance_variable_set("@#{name}", Person.new)
end

@john       
# => #<Person:0x007f9734089530>
def foo
  a = 1
  bind = binding
  bind.local_variable_set(:a, 2) # set existing local variable `a'
  bind.local_variable_set(:b, 3) # create new local variable `b'
                                 # `b' exists only in binding

  p bind.local_variable_get(:a)  #=> 2
  p bind.local_variable_get(:b)  #=> 3
  p a                            #=> 2
  p b                            #=> NameError
end
people_names.each { |name| eval("#{name} = Person.new")}