理解 Ruby 符号作为方法调用

13
class A
   def test
       "Test from instance"
   end
   class << self
       def test
           "Test from class"
       end
    end
end

p A.send(:test)    # "Test from class"
p A.new.method(:test).call  # "Test from instance"

这里符号按预期工作,但在这里:

s="test"
s1=:s
p s1   # :s

为什么这里会打印 :s?我不理解背后的原因。请问有人能为我解释一下吗?

5个回答

18

符号是一种轻量级的字符串(虽然它们不是字符串)。send()method()方法可以接受字符串或符号;其中一个会在内部转换为另一个(不确定是哪个),然后Ruby使用相匹配的名称执行方法。因此,A.send(:text)等价于A.text()。如果你有一个名为methodName = : text的变量,你可以做到A.send(methodName),但不能做到A.methodName()

符号不是变量,因此无法将值分配给符号。在您的示例中,符号:s与变量s无关(尽管它们具有相同的“名称”,将其放在冒号之前使其成为符号而不是变量)。您正在将字符串值分配给变量s,但告诉它打印符号:s,它就会这样做。


4
符号只是一种特殊的类似字符串的值,比普通字符串更有效率,运行时处理起来更容易。它们不是方法或变量或其他什么东西。
当你执行 A.send(:test) 时,你只是在说“嘿,A,调用名为'test'的方法”。你并没有发送方法本身,只是名称;是在 send 内部的逻辑负责查找要调用的实际方法。
当你使用 A.new.method(:test) 请求方法时,传递给 method 的只是名称“test”,而不是定义了该名称的方法。由 method 使用名称并找到实际方法以便返回它,然后你对其进行 call。你不能像 :test 这样对一个符号进行 call,因为它只是一个名称。

3
s="test"
s1=:s
p :s.object_id  #137448
p s.object_id   #77489950
p s1.object_id  #137448

我现在明白了。我分配了一个符号,但却期望一个字符串。

3

来自https://dev59.com/JHM_5IYBdhLWcg3wt1vD#1255362:

p foo会输出foo.inspect的值,即它打印出inspect的值而不是to_s的值,这对于调试更加合适(因为你可以区分1"1""2\b1"之间的差异,而在不使用inspect打印时无法区分)。


嘿,我现在明白了...我太傻了,不知道p和puts之间的区别。谢谢。 - sunny1304

2
你将s1的值设置为:s,那么你为什么期望它返回不同的内容呢?
如果你查看Ruby API中的Object类,你会发现Object#sendObject#method都接受符号作为参数,所以第一个示例也是完全符合预期的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接