【问题标题】:Usage of symbols and table of symbols符号的使用和符号表
【发布时间】:2013-01-23 04:00:24
【问题描述】:
  1. 在许多 Rails 方法中,符号作为参数传递。我不确定其中一些参数是如何引用其他方法的。换句话说,符号指向另一种方法。我理解像:something 这样的符号将始终指向相同的内存分配,这与"something" 的多个实例不同。如果我有一个符号:x,并且还定义了一个方法x(),是否意味着这两者以某种方式联系在一起?

  2. A Ruby book 描述了符号表的概念:

    符号是一个标识符,其值为自身。从广义上讲,这从 Ruby 程序员的角度描述了符号的行为方式。但它并没有从 Ruby 解释器的角度告诉您字面上的符号是什么。实际上,符号是指向符号表的指针。符号表是 Ruby 的内部已知标识符列表——例如变量和方法名。

    我偶然发现它是如何引用不同的方法或字符串的。谁能帮我理解这个符号表以及它与用作方法名称的符号有何关系?

【问题讨论】:

  • 你能发布一个令人困惑的“使用符号作为方法名称”的 sn-p 吗?以便我们知道您在说什么。

标签: ruby symbols


【解决方案1】:

符号本身与方法没有任何联系。某些方法可以接受符号来动态调用其他方法,使用符号作为它们的名称。观察:

class Foo
  def bar
    "called bar"
  end

  def baz
    "called bazzz"
  end

  def invoke m
    send m
  end
end

f = Foo.new
f.invoke :bar # => "called bar"
f.invoke :baz # => "called bazzz"

# since `invoke` just delegates execution to `send`, and `send` can accept strings as well
#   we can pass a string here. 
f.invoke 'baz' # => "called bazzz"

这与中的情况相同

before_filter :init_session
validates_presence_of :first_name

还有很多其他

编辑:

如果我有一个符号 :x 并且还定义了一个方法 x(),这是否意味着这两个以某种方式链接?

,它们没有以任何方式链接。您可以放心地忽略有关符号表的那段内容。目前对您来说这是不必要的实现细节。

【讨论】:

  • 感谢塞尔吉奥的回复。例如,使用 attr_accessor 方法,您可以为不同的 getter 和 setter 方法传递符号。 ruby 怎么知道如果我传递 :name,它应该引用 name() 和 name=()?在您的示例中,Ruby 如何知道动态调用其他方法?
  • 我的示例使用send 方法来动态调用方法。至于attr_accessor,这里有多个答案(总之,它使用传递符号:name来定义两个方法,namename=
  • 您的invokef.invoke 'bar'f.invoke 'baz' 一样好用,不过send 对字符串和对符号一样满意。
  • @muistooshort:是的,我知道,但他问的是符号 :)
  • @WillsonMock:invoke 不知道。 send 确实如此。它是如何做到的——不是我们的事。但我们知道它可以做这种事情。
【解决方案2】:

符号名称和方法名称没有以任何方式链接。符号与字符串的关系最为密切。字符串和符号之间的区别在于,符号是整个 Ruby 解释器的唯一对象,而字符串始终是唯一对象。为了说明这一点,打开 IRB:

irb
1.9.3-p362 :001 > "hello".object_id
 => 70162149682220 
1.9.3-p362 :002 > "hello".object_id
 => 70162149699280 
1.9.3-p362 :003 > :hello.object_id
 => 460328 
1.9.3-p362 :004 > :hello.object_id
 => 460328 
1.9.3-p362 :005 > "hello".to_sym.object_id
 => 460328 

如您所见,两个包含“hello”的相同字符串具有不同的对象 ID,即使它们包含相同的内容。另一方面,只要符号的内容相同,符号总是具有相同的对象 ID。您可以看到将字符串“hello”转换为符号会得到与符号:hello 相同的对象ID。符号的使用内存效率更高,相等比较更快。权衡是符号本质上是内存泄漏,因为一旦定义了符号,就永远无法从内存中删除它。

正如 Sergio 所说,您可以使用 send 方法调用方法,但 send 使用 Ruby 的强大反射在运行时按名称执行方法,除了方法名称由一个符号。

编辑:如果您对它的工作原理感到好奇,请查看Ruby Metaprogramming 以了解您能够做的事情。但是,要准确了解其工作原理,您需要查看 Ruby 语言的 C 源代码。

【讨论】:

    【解决方案3】:

    如果您定义了符号 :x 并且还定义了一个方法 x() 并打印 :x.class=> 符号 , x.class=> "返回字段的数据类型,或者如果没有返回则 NilClass"。

    这表明符号 :x 和方法 x() 之间没有关系。

    在 Ruby 中用 Symbol 完成的事情也可以用 String 完成。

    如果您想要一个字符串实例,则使用符号代替字符串意味着您想要一个用于特定字符串的内存位置,显然是为了提高性能。

    Ruby 在内部将方法名称保存为符号。

    因此,在传递方法名称时最好使用 Symbol,例如 attr_accessor 和 send,但这不是强制性的,否则您可以使用 String。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-15
      • 2011-02-20
      • 1970-01-01
      • 2014-01-10
      • 2017-03-03
      相关资源
      最近更新 更多