我不确定在Ruby中是否可行,但是希望有一种简单的方法。 我想声明一个变量,然后找出该变量的名称。 也就是说,对于这个简单的代码段:
我如何找回数组的名称(在这里为" foo")? 如果确实可行,这是否适用于任何变量(例如,标量,哈希等)?
编辑:这是我基本上想做的。 我正在编写一个SOAP服务器,该服务器使用三个重要变量包装了一个类,验证代码本质上是这样的:
1 2 3 4 5 6
| [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的答案)
如果您解决问题了怎么办?与其尝试从变量中获取名称,不如从名称中获取变量:
1 2 3 4 5 6 7
| ["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"以保持评估从引发异常...
您需要重新设计解决方案。即使可以(不能),问题也没有合理的答案。
想象一个get_name方法。
每个人都可能同意这应该返回" a"
它应该返回" b"或" a",还是包含两者的数组?
1 2 3
| [b,a].each do |arg|
get_name(arg)
end |
它应该返回" arg"," b"还是" a"?
1 2 3 4
| def do_stuff( arg )
get_name(arg)
do
do_stuff(b) |
它应该返回'arg','b'或'a',还是所有它们的数组?即使它确实返回了数组,其顺序也将如何,我怎么知道如何解释结果?
以上所有问题的答案是"这取决于我当时想要的特定事物。"我不确定您如何解决Ruby的问题。
看来您正在尝试解决一个容易解决的问题。
为什么不将数据仅存储在哈希中?如果你这样做..
1
| data_container = {'foo' => ['goo', 'baz']} |
..然后完全变得微不足道,以获取'foo'名称。
就是说,您尚未对该问题提供任何背景信息,因此可能有您不能执行此操作的原因。
[编辑]澄清之后,我看到了问题,但我不认为这是问题所在。使用[foo,bar,bla],就相当于说['content 1', 'content 2', 'etc']。实际的变量名称是(或者应该是)完全不相关的。如果变量的名称很重要,那就正是为什么存在哈希的原因。
问题不在于遍历[foo,bar]等,这是SOAP服务器如何重现数据和/或尝试使用它的根本问题。
我想说的解决方案是使SOAP服务器返回哈希值,或者因为您知道总会有三个元素,所以您不能做类似的事情。
1 2 3 4 5 6
| {"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 |
好的,它也可以在实例方法中工作,并且根据您的特定要求(您在注释中提出的要求),您可以执行以下操作:
1 2 3
| local_variables.each do |var|
puts var if (eval(var).class != Fixnum)
end |
只需将Fixnum替换为您的特定类型检查即可。
好问题。我完全理解你的动机。让我首先指出,存在某些特殊对象,在某些情况下,它们对已分配给变量的变量有所了解。这些特殊对象是例如。 Module实例,Class实例和Struct实例:
1 2
| Dog = Class.new
Dog.name # Dog |
要注意的是,这仅在执行赋值的变量为常数时有效。 (我们都知道Ruby常数不过是情感敏感的变量。)因此:
1 2 3 4
| 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" |
知道对象被分配了哪些变量的对象的这种行为通常称为常量魔术(因为它仅限于常量)。但是,这种高度期望的恒定魔术仅适用于某些对象:
1 2
| Rover = Dog.new
Rover.name #=> raises NoMethodError |
幸运的是,我写了一个gem y_support/name_magic,可以为您解决这个问题:
1 2 3 4 5 6
| # first, gem install y_support
require 'y_support/name_magic'
class Cat
include NameMagic
end |
实际上,这仅适用于常量(即,以大写字母开头的变量)并不是很大的限制。实际上,它使您可以随意命名或不随意命名对象:
1 2 3 4
| 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方法的。因此,要实现您想要的目标,您将必须子类Array:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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核心团队已承诺const_assigned挂钩。
有Kernel::local_variables,但是我不确定这是否适用于方法的本地var,而且我不知道您可以通过操作来实现自己想要的效果。
在joshmsmoore的基础上,可能会执行以下操作:
1 2 3 4 5 6 7
| # 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 |
我不知道以任何方式获取局部变量名称。但是,您可以使用instance_variables方法,这将返回对象中所有实例变量名称的数组。
简单的电话:
1
| object.instance_variables |
要么
获取所有实例变量名称的数组。
对于您的问题,最接近实际答案的方法是使用Enumerable方法each_with_index而不是每个方法,因此:
1 2 3 4 5 6
| 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_with_index都返回它们在其上操作的数组。
块中还有一些关于范围的注意事项:如果您在块外定义了变量,则该变量将在其中可用。换句话说,您可以直接在块内部引用foo,bar和baz。相反,事实并非如此:您在块内首次创建的变量将无法在块外使用。
最后,do / end语法是多行块的首选,但这只是样式问题,尽管它在任何最近年份的红宝石代码中都是通用的。
Foo只是保存指向数据的指针的位置。数据不知道它指向什么。在Smalltalk系统中,您可以要求VM提供指向对象的所有指针,但这只会使您获得包含foo变量的对象,而不是foo本身。在Ruby中没有真正的方法来引用可用商品。就像一个答案提到的那样,您可以在数据中放置一个标记,以引用它的来源,但通常这并不是解决大多数问题的好方法。您可以首先使用散列来接收值,也可以使用散列来传递给循环,这样您就可以像DBR的答案一样知道用于验证目的的参数名称。
不能,您需要返回到绘图板上并重新设计您的解决方案。