符号和符号表的用法

时间:2013-01-23 04:00:24

标签: ruby symbols

  1. 在许多Rails方法中,符号作为参数传递。我不确定其中一些参数是如何引用其他方法的。换句话说,符号指向另一种方法。我理解像:something这样的符号将始终指向相同的内存分配,这与多个实例(例如"something")不同。如果我有一个符号:x并且还定义了一个方法x(),这是否意味着这两个是以某种方式链接的?

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

      

    符号是其值本身的标识符。从广义上讲,它描述了符号从Ruby程序员的角度出发的方式。但它并没有告诉你从Ruby解释器的角度来看,字面上是什么符号。实际上,符号是指向符号表的指针。符号表是Ruby的已知标识符的内部列表 - 例如变量和方法名称。

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

3 个答案:

答案 0 :(得分:7)

符号本身不以任何方式与方法相关联。某些方法可以接受符号来动态调用其他方法,使用符号作为其名称。观察:

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(),这是否意味着这两个是以某种方式链接的?

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

答案 1 :(得分: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源代码。

答案 2 :(得分:0)

如果定义symbol:x并定义方法x()并打印:x.class =>符号,x.class => “返回字段的数据类型或者如果没有返回那么NilClass”。

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

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

如果你想要一个字符串实例意味着你想要一个特定字符串的内存位置,那么使用符号而不是字符串,显然是为了提高性能。

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

因此,在传递方法名称时最好使用Symbol,就像attr_accessor和send一样,但它不是必须的,否则你可以使用String。