我不完全确定Ruby是否可行,但希望有一种简单的方法可以做到这一点。我想声明一个变量,然后找出变量的名称。也就是说,对于这个简单的片段:
foo = ["goo", "baz"]
如何获取数组的名称(此处为“foo”)?如果它确实可行,这是否适用于任何变量(例如,标量,散列等)?
编辑:这是我基本上想要做的事情。我正在编写一个包含三个重要变量的类的SOAP服务器,验证代码基本上是这样的:
[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或bar替换'param_name'的实例吗?这些对象都是数组,所以到目前为止我得到的答案似乎不起作用(除了重新设计整个事物ala dbr's answer)
答案 0 :(得分:40)
如果你扭转了问题怎么办?不要试图从变量中获取名称,而是从名称中获取变量:
["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
}
如果有可能根本没有定义变量(而不是数组),你可能想在“param = ...”行的末尾添加“rescue nil”保持eval不会抛出异常...
答案 1 :(得分:28)
您需要重新构建解决方案。即使你可以做(你做不到),这个问题根本就没有合理的答案。
想象一下get_name方法。
a = 1
get_name(a)
每个人都可能同意这应该返回'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解决这个问题。
答案 2 :(得分:8)
您似乎正在尝试解决一个容易解决的问题。
为什么不将数据存储在哈希中?如果你这样做..
data_container = {'foo' => ['goo', 'baz']}
..获得'foo'这个名字真是微不足道。
那就是说,你没有给出任何问题的背景,所以可能有理由你不能这样做..
[edit] 澄清后,我看到了问题,但我不认为这是问题..有了[foo,bar,bla],它就像说{{1} }。实际变量名称(或者更确切地说,应该是)完全不相关。如果变量的名称很重要,那就是存在哈希的原因。
问题不在于迭代[foo,bar]等,这是SOAP服务器如何撤回数据的根本问题,和/或您尝试使用它的方式。
我想说,解决方案是让SOAP服务器返回哈希值,或者,因为你知道总会有三个元素,所以你不能做类似的事情。
['content 1', 'content 2', 'etc']
答案 3 :(得分:5)
好吧,它也可以在实例方法中工作,并且根据您的具体要求(您在评论中添加的那个),您可以这样做:
local_variables.each do |var|
puts var if (eval(var).class != Fixnum)
end
只需将Fixnum
替换为您的特定类型检查。
答案 4 :(得分:2)
我不知道如何获取本地变量名称。但是,您可以使用instance_variables
方法,这将返回对象中所有实例变量名称的数组。
简单的电话:
object.instance_variables
或
self.instance_variables
获取所有实例变量名称的数组。
答案 5 :(得分:2)
在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
答案 6 :(得分:2)
有Kernel::local_variables
,但我不确定这是否适用于某个方法的本地变量,而且我不知道你可以通过这样的方式操作它来做你想做的事情。
答案 7 :(得分:2)
好问题。我完全理解你的动机。让我首先指出,有某些特殊对象,在某些情况下,它们知道变量,它们已被分配给它们。这些特殊对象是例如。 Module
个实例,Class
个实例和Struct
个实例:
Dog = Class.new
Dog.name # Dog
问题是,只有当执行赋值的变量是常量时,这才起作用。 (我们都知道Ruby常量只不过是情绪敏感的变量。)因此:
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"
对象的这种行为意识到它们已分配给哪些变量,通常称为常量魔法(因为它仅限于常量)。但是这个非常理想的常量魔法仅适用于某些对象:
Rover = Dog.new
Rover.name #=> raises NoMethodError
幸运的是,I have written a gem y_support/name_magic
,为您解决了这个问题:
# first, gem install y_support
require 'y_support/name_magic'
class Cat
include NameMagic
end
事实上,这只适用于常量(即以大写字母开头的变量)并不是一个很大的限制。实际上,它允许您自由命名或不命名您的对象:
tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie
不幸的是,这不适用于数组文字,因为它们是在内部构造的,而不使用#new
依赖的NameMagic
方法。因此,要实现您想要的目标,您必须继承Array
:
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
通过搜索当前Ruby对象空间的所有命名空间中的所有常量,我实现了不断的魔术模仿行为。这浪费了一小部分时间,但由于搜索只执行一次,因此一旦对象找出其名称,就不会有性能损失。将来,Ruby核心团队has promised const_assigned
hook。
答案 8 :(得分:1)
你不能,你需要回到绘图板并重新设计你的解决方案。
答案 9 :(得分:1)
Foo只是一个保存指向数据的指针的位置。数据不知道它的含义。在Smalltalk系统中,您可以向VM请求指向对象的所有指针,但这只会获得包含foo变量的对象,而不是foo本身。没有真正的方法来引用Ruby中的vaiable。正如一个答案中所提到的,你可以在数据中放置一个标记来引用它来自哪里或者这样,但通常这对大多数问题来说都不是一个好的选择。您可以使用哈希来首先接收值,或使用哈希传递给您的循环,以便您知道参数名称以进行验证,如DBR的答案。
答案 10 :(得分:1)
对你问题的真正答案最接近的是使用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_with_index的块中删除了return语句,因为它没有/表示任何内容。 each和each_with_index都返回它们正在运行的数组。
还有一些关于块的范围值得注意:如果你已经在块之外定义了一个变量,它将在其中可用。换句话说,您可以直接在块内引用foo,bar和baz。反之亦然:您在块内首次创建的变量将无法在其外部使用。
最后,do / end语法是多行块的首选,但这只是一种风格问题,尽管它在任何最近年代的ruby代码中都是通用的。