符号和变量
要了解符号(symbol)和标识符(例如变量名称)之间的关系,请查看我们的 symbols_2.rb 程序。首先将值 1 赋给局部变量 x
。然后将符号 :x
赋给局部变量 xsymbol
…
x = 1
xsymbol = :x
此时,变量 x
和符号 :x
之间没有明显的联系。我声明了一个方法,它只需要一些传入参数并使用 p
方法查看(inspects)和显示它。我可以使用变量和符号调用此方法:
# Test 1
amethod( x )
amethod( :x )
这是该方法打印的数据结果:
1
:x
换句话说,x
变量的值是 1,因为那是分配给它的值,而 :x
的值是 :x
。但是出现了有趣的问题:如果 :x
的值是 :x
并且这也是变量 x
的符号名称,是否可以使用符号 :x
来查找变量 x
的值?困惑?希望下一行代码能这些更清楚:
# Test 2
amethod( eval(:x.id2name))
这里,id2name
是 Symbol 类的一个方法。它返回与符号对应的名称或字符串(to_s
方法将执行相同的功能);最终结果是,当给出符号 :x
作为参数时,id2name
返回字符串 “x”。Ruby 的 eval
方法(在 Kernel 类中定义)能够计算字符串中的表达式。在本例中,这意味着它找到字符串 “x” 并尝试将其作为可执行代码进行计算。它发现 x
是变量的名称,并且 x
的值是 1。所以值 1 传递给 amethod
。你可以通过运行 symbols2.rb 和比较代码的输出结果来验证这一点。
事情变得更加诡异。请记住,变量 xsymbol
已被赋予符号 :x
…
x = 1
xsymbol = :x
这意味着如果我们 eval :xsymbol
,我们可以获得分配给它的名称 - 即符号 :x
。获得 :x
后我们可以继续计算它,给出 x
的值 - 即 1:
# Test 3
amethod( xsymbol ) #=> :x
amethod( :xsymbol ) #=> :xsymbol
amethod( eval(:xsymbol.id2name)) #=> :x
amethod( eval( ( eval(:xsymbol.id2name)).id2name ) ) #=> 1
正如我们所见,当用于创建属性访问器(attribute accessors)时,符号可以引用方法名称。我们可以利用它将方法名称作为符号传递给 method
方法(是的,确实存在一个名为'method'
的方法),然后使用 call
方法调用指定的方法:
#Test 4
method(:amethod).call("")
call
方法允许我们传递参数,为了方便,我们可以通过计算符号来传递一个参数:
method(:amethod).call(eval(:x.id2name))
如果这看起来很复杂,请看一下 symbols_3.rb 中的一个更简单的示例。这从以下赋值开始:
def mymethod( somearg )
print( "I say: " << somearg )
end
this_is_a_method_name = method(:mymethod)
这里 method(mymethod)
查找一个方法,该方法的名称由作为参数传递的符号(:mymethod
)指定,如果找到,则返回具有相应名称的 Method 对象。在我的代码中,我有一个名为 mymethod
的方法,现在将其分配给变量 this_is_a_method_name
。
运行此程序时,你将看到第一行输出打印了变量的值:
puts( this_is_a_method_name ) #=> This displays: #<Method: Object#mymethod>
这表明变量 this_is_a_method_name
已被赋予了方法 mymethod
,该方法绑定到 Object 类(所有方法都作为’独立’(freestanding)函数输入)。要仔细检查变量是否真的是 Method 类的一个实例,下一行代码会打印出它的类:
puts( "#{this_is_a_method_name.class}" ) #=> This displays: Method
好吧,如果它真的是一个真正的方法,那么我们应该可以调用它,不是吗?为此,我们需要使用 call
方法。这就是最后一行代码的作用:
this_is_a_method_name.call( "hello world" ) #=> This displays: I say: hello world