我正在尝试理解 Ruby,但我不清楚 Ruby 如何将方法名称转换为Symbol
?
在方法定义中我们给它一个名字meth
module Mod
def meth
puts 'm'
end
end
但是如果我们想检查一个方法是否存在,我们将符号:meth
作为参数传递给method_defined
Mod.method_defined?(:meth)
=> true
请帮助我理解,这是如何工作的?
我正在尝试理解 Ruby,但我不清楚 Ruby 如何将方法名称转换为Symbol
?
在方法定义中我们给它一个名字meth
module Mod
def meth
puts 'm'
end
end
但是如果我们想检查一个方法是否存在,我们将符号:meth
作为参数传递给method_defined
Mod.method_defined?(:meth)
=> true
请帮助我理解,这是如何工作的?
这是由于 ruby 的方法调用语法:您可以仅通过引用其名称来调用方法,而无需任何其他语法,例如()
需要括号。
现在,如果该method_defined?
方法将方法本身作为参数,那么如果不实际调用该方法并因此在该方法不存在时产生错误,就没有办法这样做:
Mod.method_defined?(meth)
#=> NameError: undefined local variable or method `meth'
使用符号,不会发生调用,它只是正常实例化并且不会产生任何错误。在幕后,method_defined?
然后可以通过符号引用的名称查找方法是否存在而不会产生任何错误。
与其说一个方法“变成”一个符号,不如说它可以被符号引用。
当我们查看 ObjectSpace.methods 中的方法集合时,我们看到这些对象被称为符号。
这是有道理的,因为 Ruby 中的符号非常高效,因为只有一个对象是那个符号,它们是不可变的,它可以根据上下文引用它需要的内容,引用范围和“自我”所在的位置此时此刻。
换句话说,被调用的符号:to_s
将是相同的符号,无论它在哪里被引用。它的 object_id 总是相同的,但它可能引用 Array 的to_s
方法,甚至是一个名为 的局部变量to_s
。
方法定义?(符号)→真或假
方法定义?(字符串)→真或假
如果命名方法由 mod(或其包含的模块,如果 mod 是一个类,它的祖先)定义,则返回 true。公共和受保护的方法是匹配的。字符串参数被转换为符号。
这意味着-method_defined?
方法总是期望符号作为它的参数,但是如果你使用字符串,那么它会在内部使用String#to_sym
.
标识符也需要存储在内存中。所有语言都以某种形式存储方法名称、类名称。他们只是不像 Ruby 那样使这些易于访问。类名存储为常量。方法名称存储为符号。没有什么可以转换为 Symbol 的。它始终作为符号存储。这使得以下成为可能:
1.send(:+, 3) # exactly same as 1+3
这也意味着您实际上可以接受来自用户的名称并执行该特定方法。你总是可以通过 switch/if-else 做到这一点,但这确实从功能中删除了一层。例如
case option
when '+'
variable1 + variable2
when '-'
variable1 - variable2
when '*'
variable1 * variable2
when '/'
variable1 / variable2
end
相比
variable1.send(option, variable2)
你看到它的天才了吗?
我不清楚,Ruby如何将方法名转换为:symbol?
这就是工作方式Method#name
,它将方法的名称作为符号返回:
m = "foo".method(:size) #=> #<Method: String#size>
m.name #=> :size
m.call #=> 3
所有引用其他方法的方法通常都以这种方式工作。例如,Object#methods
返回一个方法名数组:
"foo".methods
#=> [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, ...]
在方法定义中,我们给它命名
meth
......但是如果我们想检查,是否存在任何方法,我们给method_defined
符号:meth
meth
将是对变量或其他方法的引用,而:meth
只是一个符号:
meth = :foo
Mod.method_defined? meth #=> false, equivalent to Mod.method_defined? :foo
Mod.method_defined? :meth #=> true