符号与字符串
一个常见的误解就是认为符号(symbol)是字符串的一种类型。毕竟,符号 :hello
与字符串 “hello” 非常相似不是吗?
事实上,符号与字符串完全不同。首先,每个字符串是不同的 — 因此,”hello”、”hello” 和 “hello” 是三个独立的对象,具有三个独立的 object_id
s。
puts( "hello".object_id ) # These 3 strings have 3 different object_ids
puts( "hello".object_id )
puts( "hello".object_id )
但是符号是唯一的,所以 :hello
、:hello
和 :hello
都引用具有相同的 object_id
的对象。在这方面,符号与整数(integer)相比,要比字符串有更多的共同之处。你可能还记得,给定的整数值每次出现都引用相同的对象,因此 10
、10
和 10
可以被认为是相同的对象,并且它们具有相同的 object_id
:
# These three symbols have the same object_id
puts( :ten.object_id )
puts( :ten.object_id )
puts( :ten.object_id )
# These three integers have the same object_id
puts( 10.object_id )
puts( 10.object_id )
puts( 10.object_id )
或者你可以使用 equal?
方法测试其相等性:
puts( :helloworld.equal?( :helloworld ) ) #=> true
puts( "helloworld".equal?( "helloworld" ) ) #=> false
puts( 1.equal?( 1 ) ) #=> true
由于是唯一的,所以符号提供了明确的标识符。你可以将符号作为参数传递给方法,如下所示:
amethod( :deletefiles )
方法可能包含测试传入参数的值的代码:
def amethod( doThis )
if (doThis == :deletefiles) then
puts( 'Now deleting files...')
elsif (doThis == :formatdisk) then
puts( 'Now formatting disk...')
else
puts( "Sorry, command not understood." )
end
end
符号还可用于提供字符串的可读性和整数的唯一性的 case
语句:
case doThis
when :deletefiles : puts( 'Now deleting files...')
when :formatdisk : puts( 'Now formatting disk...')
else puts( "Sorry, command not understood." )
end
声明符号的作用域不会影响其唯一性。思考以下…
module One
class Fred
end
$f1 = :Fred
end
module Two
Fred = 1
$f2 = :Fred
end
def Fred()
end
$f3 = :Fred
这里,变量 $f1
,$f2
和 $f3
在三个不同的作用域内分配了符号 :Fred
:模块 One,模块 Two 和 ‘main’ 作用域。我将在第 12 章中对模块(modules)进行更多说明。现在,只需将它们视为定义不同作用域的“命名空间”(namespaces)即可。然而每个变量引用着相同的符号 :Fred
,并且具有相同的 object_id
:
# All three display the same id!
puts( $f1.object_id )
puts( $f2.object_id )
puts( $f3.object_id )
即便如此,符号的“含义”(meaning)也会根据其作用域而变化。
换句话说,在模块 One 中,:Fred
引用类 Fred
,在模块 Two 中,它引用常量 Fred = 1
,在 main 作用域内引用 Fred
方法。
上一个程序的重写版本证实了这一点:
module One
class Fred
end
$f1 = :Fred
def self.evalFred( aSymbol )
puts( eval( aSymbol.id2name ) )
end
end
module Two
Fred = 1
$f2 = :Fred
def self.evalFred( aSymbol )
puts( eval( aSymbol.id2name ) )
end
end
def Fred()
puts( "hello from the Fred method" )
end
$f3 = :Fred
One::evalFred( $f1 ) #=> displays the module::class name: One::Fred
Two::evalFred( $f2 ) #=> displays the Fred constant value: 1
method($f3).call #=> calls Fred method: displays: "hello from the Fred method"
当然,由于变量 $f1
,$f2
和 $f3
引用着相同的符号,因此你使用的变量是在任意地方指定的都是无关紧要的。以下产生完全相同的结果:
One::evalFred( $f3 )
Two::evalFred( $f1 )
method($f2).call