我不完全确定这在 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的回答)

有帮助吗?

解决方案

如果你扭转问题怎么办?不要尝试从变量中获取名称,而是从名称中获取变量:

["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
  }

如果有可能根本没有定义变量(而不是不是数组),您需要将“rescue nil”添加到“param = ...”行的末尾以保留 eval从抛出异常...

其他提示

您需要重新构建您的解决方案。即使你 可以 这样做(你不能),这个问题根本没有合理的答案。

想象一下 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解决这个问题。

看来你正在尝试解决一个更容易解决的问题。

为什么不将数据存储在哈希中呢?如果你这样做..

data_container = {'foo' => ['goo', 'baz']}

..然后获取“foo”名称就变得微不足道了。

也就是说,您没有给出该问题的任何背景信息,因此可能有一个原因您无法执行此操作。

[编辑] 澄清后,我看到了这个问题,但我不认为这就是问题所在。对于 [foo, bar, bla],相当于说 ['content 1', 'content 2', 'etc']. 。实际的变量名称是(或者更确切地说,应该是)完全不相关的。如果变量的名称很重要,这就是散列存在的原因。

问题不在于迭代 [foo, bar] 等,而在于 SOAP 服务器如何返回数据和/或如何尝试使用它。

我想说,解决方案是要么让 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

好的,它也可以在实例方法中工作,并且根据您的具体要求(您在评论中提出的要求),您可以这样做:

local_variables.each do |var|
  puts var if (eval(var).class != Fixnum)
end

只需更换 Fixnum 与您的特定类型检查。

我不知道有什么方法可以获取局部变量名。但是,您可以使用 instance_variables 方法,这将返回对象中所有实例变量名称的数组。

简单的调用:

object.instance_variables

或者

self.instance_variables

获取所有实例变量名称的数组。

建立在 乔什莫尔, ,这样的事情可能会做到这一点:

# 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, ,但我不确定这是否适用于方法的本地变量,并且我不知道您可以以某种方式操纵它来实现您希望实现的目标。

很好的问题。我完全理解你的动机。首先让我指出,有某些类型的特殊对象,在某些情况下,它们了解它们所分配的变量。这些特殊物体是例如。 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

幸运的是, 我写了一篇宝石 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核心团队 已承诺 const_assigned.

你不能,你需要回到绘图板并重新设计你的解决方案。

Foo 只是保存指向数据的指针的位置。数据不知道它指向什么。在 Smalltalk 系统中,您可以向 VM 请求所有指向对象的指针,但这只会为您提供包含 foo 变量的对象,而不是 foo 本身。在 Ruby 中没有真正的方法来引用变量。正如一个答案所提到的,您仍然可以在数据中放置一个标签来引用数据的来源等,但通常这对于大多数问题来说并不是一个好的方法。您可以首先使用哈希来接收值,或者使用哈希传递到循环,以便您知道用于验证目的的参数名称,如 DBR 的答案所示。

最接近您问题的真正答案的是使用 Enumerable 方法each_with_index 而不是each,因此:

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_with_index 都返回它们正在操作的数组。

这里还有一些关于块范围的事情值得注意:如果您在块外定义了变量,则该变量在块内可用。换句话说,您可以直接在块内引用 foo、bar 和 baz。反之则不然:您在块内首次创建的变量在块外部将不可用。

最后,do/end 语法是多行块的首选,但这只是风格问题,尽管它在最近的任何版本的 ruby​​ 代码中都是通用的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top