我是Ruby的新手,和其他人一样,我在用Ruby符号包裹头时遇到了麻烦。我知道这个话题已经提出很多次了,但是我相信这篇文章可能与其他文章略有不同。如果没有,我表示歉意。以documentation中的这段代码为例。
module One
class Fred
end
$f1 = :Fred
end
module Two
Fred = 1
$f2 = :Fred
end
def Fred()
end
$f3 = :Fred
$f1.object_id #=> 2514190
$f2.object_id #=> 2514190
$f3.object_id #=> 2514190
我的抱怨是,这使我们认为类,模块或函数与:Fred
符号之间存在联系。难怪人们会问诸如“我可以为符号分配值”之类的问题吗?还是该符号是对其他事物的引用。
此代码加剧了混乱:
class TestController < ApplicationController
layout :which_layout
def index
...
end
private
def which_layout
if condition
"layout1"
else
"layout2"
end
end
end
起初,我以为是对函数的引用,但实际上,layout方法的行为会根据我们是否传递String
(模板名称)而有所不同。 )或文档中所述的Symbol
(调用由符号指定的方法)。 (它是否查找与我们作为参数传递的符号等效的method.to_sym
?)
但是我相信我已经读过的是,在创建类时,将自动创建其对应的符号,即:Fred在后续调用中已经存在。就是这样吗?
我的问题是:为什么他们必须包含一个类,一个变量和一个函数来说明这一点?上下文?那为什么要起同样的名字呢?为什么不做:
$f1 = :Fred
$f2 = :Fred
$f3 = :Fred
$f1.object_id #=> 2514190
$f2.object_id #=> 2514190
$f3.object_id #=> 2514190
答案 0 :(得分:2)
使用符号时,Ruby会查看现有符号的列表,因此当您重复使用符号时,不会在内存中创建单独的对象。
irb(main):006:0> :foo.object_id == :foo.object_id
=> true
您可以将其与字符串进行对比:
irb(main):007:0> "foo".object_id == "foo".object_id
=> false
再加上它们比较便宜的事实,使符号像哈希键一样有效。
这个令人困惑的例子说明,符号不是作用域专用的-符号表是全局的。如果使用实例变量而不是全局变量,将会减少混乱。我认为它也试图证明模块和类名是常量。
irb(main):016:0> Fred = Module.new do; end # this is the same as using the module keyword
irb(main):017:0> Fred.object_id != :Fred.object_id
=> true
这意味着Fred
是对该模块的引用,而:Fred
是一个值(符号)。
像字符串这样的符号是一个值,因此不能用作参考。这非常类似于true
,false
和nil
,它们是单例对象。
irb(main):008:0> true.class
=> TrueClass
irb(main):09:0> true.object_id == true.object_id
=> true
# you can even use the singletons as hash keys
irb(main):010:0> { true => 1, false => 2, nil => 3 }[true]
=> 1
Rails示例并没有那么复杂。 :which_layout
只是传递给layout方法的参数。 layout方法有一个条件,该条件使用Object#send动态调用:which_layout方法(如果存在)。而是直接使用字符串参数来构造glob。
答案 1 :(得分:0)
我的理解是,它说明所有其他“弗雷德的”都无济于事,无法改变符号:Fred
在每种情况下都是不变的事实。也许将示例底部的object_id
列表更改为类似的内容,这样会更清楚:
p One::Fred.object_id #=> 70222371662500
p Two::Fred.object_id #=> 3
p Fred().object_id #=> 8
p $f1.object_id #=> 2514190
p $f2.object_id #=> 2514190
p $f3.object_id #=> 2514190