在Ruby中按名称访问variables
我不完全确定这是否可能在Ruby中,但希望有一个简单的方法来做到这一点。 我想声明一个variables,然后找出variables的名称。 也就是说,对于这个简单的片段:
foo = ["goo", "baz"]
我怎样才能得到数组的名称(在这里,“富”)? 如果确实有可能,这是否适用于任何variables(例如,标量,哈希等)?
编辑:这是我基本上试图做的。 我正在写一个SOAP服务器,用三个重要的variables包装一个类,validation代码本质上是这样的:
[foo, goo, bar].each { |param| if param.class != Array puts "param_name wasn't an Array. It was a/an #{param.class}" return "Error: param_name wasn't an Array" end }
我的问题是:我可以使用foo,goo或barreplace“param_name”的实例吗? 这些对象都是数组,所以我迄今收到的答案似乎并不奏效(除了重新deviseala dbr的答案 )
如果你把问题转过来呢? 不要试图从variables中获取名称,而是从名称中获取variables:
["foo", "goo", "bar"].each { |param_name| param = eval(param_name) if param.class != Array puts "#{param_name} wasn't an Array. It was a/an #{param.class}" return "Error: #{param_name} wasn't an Array" end }
如果有一个variables没有被定义的可能性(而不是一个数组),你可能想要在“param = …”行的末尾添加“rescue nil”来保持eval从抛出一个例外…
您需要重新构build您的解决scheme。 即使你能做到(不行),这个问题根本就没有合理的答案。
想象一下get_name方法。
a = 1 get_name(a)
每个人都可能认同这应该返回'一个'
b = a get_name(b)
它应该返回'b','a'还是包含两者的数组?
[b,a].each do |arg| get_name(arg) end
应该返回“arg”,“b”还是“a”?
def do_stuff( arg ) get_name(arg) do do_stuff(b)
它应该返回“arg”,“b”还是“a”,或者是所有这些数组? 即使它返回一个数组,那么顺序是什么,我怎么知道如何解释结果呢?
上述所有问题的答案是“这取决于我当时想要的东西”。 我不知道如何解决Ruby的这个问题。
看来你正试图解决一个更容易解决的问题..
为什么不把数据存储在一个散列? 如果你做..
data_container = {'foo' => ['goo', 'baz']}
那么得到'foo'这个名字是非常简单的。
也就是说,你没有给出任何问题的背景,所以可能有一个原因,你不能这样做..
澄清后,我看到了这个问题,但我不认为这是问题。与[foo,bar,bla],它相当于说['content 1', 'content 2', 'etc']
。 实际的variables名是(或者说应该是)完全不相关的。 如果variables的名字是重要的,那就是为什么哈希存在。
问题不在于[foo,bar]迭代,这是SOAP服务器如何callback数据和/或如何使用它的根本问题。
我想说的解决scheme是让SOAP服务器返回哈希,或者,因为你知道总会有三个元素,你能不能做点什么。
{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param| if param.class != Array puts "#{param_name} wasn't an Array. It was a/an #{param.class}" puts "Error: #{param_name} wasn't an Array" end end
好吧,它也可以在实例方法中工作,根据您的具体要求(您在注释中input的内容),您可以这样做:
local_variables.each do |var| puts var if (eval(var).class != Fixnum) end
只需用您的特定types检查来replaceFixnum
。
我不知道有什么办法得到一个本地variables名称。 但是,您可以使用instance_variables
方法,这将返回对象中所有实例variables名称的数组。
简单的电话:
object.instance_variables
要么
self.instance_variables
获取所有实例variables名称的数组。
build立在joshmsmoore ,这样的事情可能会做到这一点:
# Returns the first instance variable whose value == x # Returns nil if no name maps to the given value def instance_variable_name_for(x) self.instance_variables.find do |var| x == self.instance_variable_get(var) end end
有Kernel::local_variables
,但我不确定这是否适用于方法的局部variables,而且我不知道你可以通过这样的方式来操作它,以达到你想达到的效果。
伟大的问题。 我完全理解你的动机。 首先让我注意的是,有一些特殊的对象,在某些情况下,他们已经知道了variables的分配。 这些特殊对象是例如。 Module
实例, Class
实例和Struct
实例:
Dog = Class.new Dog.name # Dog
值得注意的是,这只有当执行赋值的variables是一个常量时才起作用。 (我们都知道Ruby常量只不过是情绪敏感的variables。)因此:
x = Module.new # creating an anonymous module x.name #=> nil # the module does not know that it has been assigned to x Animal = x # but will notice once we assign it to a constant x.name #=> "Animal"
对象的这种行为意识到它们被分配了哪些variables,通常称为常量魔法 (因为它限于常量)。 但是这个非常可取的常量魔法只适用于某些对象:
Rover = Dog.new Rover.name #=> raises NoMethodError
幸运的是, 我写了一个gem y_support/name_magic
,为您处理这个问题:
# first, gem install y_support require 'y_support/name_magic' class Cat include NameMagic end
事实上,这只适用于常量(即以大写字母开头的variables)并不是一个很大的限制。 事实上,它给你自由命名或不随意命名你的对象:
tmp = Cat.new # nameless kitty tmp.name #=> nil Josie = tmp # by assigning to a constant, we name the kitty Josie tmp.name #=> :Josie
不幸的是,这不适用于数组文字,因为它们在内部构造而不使用NameMagic
依赖的#new
方法。 因此,要实现你想要的,你将不得不inheritanceArray
:
require 'y_support/name_magic' class MyArr < Array include NameMagic end foo = MyArr.new ["goo", "baz"] # not named yet foo.name #=> nil Foo = foo # but assignment to a constant is noticed foo.name #=> :Foo # You can even list the instances MyArr.instances #=> [["goo", "baz"]] MyArr.instance_names #=> [:Foo] # Get an instance by name: MyArr.instance "Foo" #=> ["goo", "baz"] MyArr.instance :Foo #=> ["goo", "baz"] # Rename it: Foo.name = "Quux" Foo.name #=> :Quux # Or forget the name again: MyArr.forget :Quux Foo.name #=> nil # In addition, you can name the object upon creation even without assignment u = MyArr.new [1, 2], name: :Pair u.name #=> :Pair v = MyArr.new [1, 2, 3], ɴ: :Trinity v.name #=> :Trinity
通过search当前Ruby对象空间的所有命名空间中的所有常量,我实现了不变的模仿行为。 这浪费了很less的时间,但是由于search只执行一次,所以一旦对象找出它的名字,就没有性能损失。 将来,Ruby核心团队已经承诺const_assigned
钩子 。
你不能,你需要回到绘图板并重新devise你的解决scheme。
Foo只是一个指向数据的指针。 数据不知道在哪个点上。 在Smalltalk系统中,您可以向VM请求所有指向对象的指针,但是这只会让您获得包含foovariables的对象,而不是foo本身。 在Ruby中没有真正的方法来引用variables。 正如一个答案所提到的,你可以在数据中加上一个标签来引用它来自哪里,但通常对于大多数问题来说这不是一个好的方法。 您可以使用哈希来首先接收值,或使用散列传递到您的循环,因此您知道参数名称用于validation目的,如在DBR的答案。
最接近真正的答案给你的问题是使用Enumerable方法each_with_index而不是每个,因此:
my_array = [foo, baz, bar] my_array.each_with_index do |item, index| if item.class != Array puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}" end end
我从你传递给each / each_with_index的块中删除了return语句,因为它没有任何意义。 each和each_in_index都返回它们所在的数组。
这里还有一些关于作用域的内容,值得注意的是:如果你已经在块外定义了一个variables,它将在其中被使用。 换句话说,你可以直接在块内引用foo,bar和baz。 反之亦然:在块内第一次创build的variables将不可用。
最后,do / end语法对于多行块是首选,但这只是一个风格问题,尽pipe它在任何最近年份的ruby代码中都是通用的。