在许多 Rails 方法中,符号作为参数传递。我不确定其中一些参数是如何引用其他方法的。换句话说,符号指向另一种方法。我了解符号 like
:something
将如何始终指向相同的内存分配,这与"something"
. 如果我有一个符号:x
并且还定义了一个方法x()
,这是否意味着这两者以某种方式联系在一起?一本 Ruby 书籍描述了符号表的概念:
符号是一个标识符,其值为自身。从广义上讲,这从 Ruby 程序员的角度描述了符号的行为方式。但它并没有告诉你从 Ruby 解释器的角度来看什么是字面上的符号。实际上,符号是指向符号表的指针。符号表是 Ruby 的内部已知标识符列表——例如变量和方法名。
我偶然发现它是如何指代不同的方法或字符串的。有人可以帮我理解这个符号表以及它与用作方法名称的符号的关系吗?
3 回答
符号本身与方法没有任何联系。某些方法可以接受符号来动态调用其他方法,使用符号作为它们的名称。观察:
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(),这是否意味着这两个以某种方式链接?
不,它们没有任何联系。您可以放心地忽略有关符号表的那段内容。目前对您来说这是不必要的实现细节。
符号名称和方法名称没有以任何方式链接。符号与字符串的关系最为密切。字符串和符号之间的区别在于,符号是整个 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" 转换为 symbol 会得到与 symbol 相同的对象 id :hello
。符号的使用内存效率更高,并且相等比较更快。权衡是符号本质上是内存泄漏,因为一旦定义它,就永远无法从内存中删除它。
正如 Sergio 所说,您可以使用方法调用方法send
,但send
使用 Ruby 的强大反射在运行时按名称执行方法,除了方法名称由符号标识之外,它与符号无关。
编辑:如果您对它的工作原理感到好奇,请查看Ruby Metaprogramming以了解您能够做的事情。但是,要准确了解其工作原理,您需要查看 Ruby 语言的 C 源代码。
如果您定义了符号 :x 并且还定义了一个方法 x() 并打印 :x.class => Symbol ,x.class =>“返回字段的数据类型,或者如果没有返回则 NilClass”。
这表明符号 :x 和方法 x() 之间没有关系。
用 Symbol 完成的事情也可以用 Ruby 中的 String 完成。
如果您想要一个字符串实例,则使用符号代替字符串意味着您想要一个用于特定字符串的内存位置,显然是为了提高性能。
Ruby 在内部将方法名称保存为符号。
因此,在传递方法名称时最好使用 Symbol ,例如 attr_accessor 和 send ,但这不是强制性的,否则您可以使用 String 。