Calling Methods
调用方法
调用方法会向对象发送消息,以便它可以执行一些工作。
在 ruby 中,你发送一条消息给像这样的对象:
my_method()
请注意,括号是可选的:
my_method
除了使用括号和省略括号之间的区别之外,本文档在存在参数时使用括号以避免混淆。
本节仅介绍调用方法。另请参阅定义方法的语法文档。
接收器
self
是默认的接收器。如果您没有指定self
将使用任何接收器。要指定接收器使用.
:
my_object.my_method
这发送my_method
消息my_object
。任何对象都可以是接收者,但取决于方法的可见性,发送消息可能会引发 NoMethodError。
你可以&.
用来指定一个接收者,然后my_method
不被调用,结果是nil
接收者时nil
。在这种情况下,参数my_method
不会被评估。
您也可以::
用来指定一个接收器,但由于可能与::
名称空间混淆,所以很少使用。
参数
发送消息时有三种类型的参数,位置参数,关键字(或命名)参数和块参数。发送的每条消息都可以使用一个,两个或所有类型的参数,但参数必须按此顺序提供。
Ruby 中的所有参数都是通过引用传递的,并不会被懒惰地评估。
每个参数由一个,fen
分离:
my_method(1, '2', :three)
参数可以是表达式,哈希参数:
'key' => value
或关键字参数:
key: value
散列和关键字参数必须是连续的,并且必须出现在所有位置参数之后,但可能是混合的:
my_method('a' => 1, b: 2, 'c' => 3)
位置参数
消息的位置参数遵循方法名称:
my_method(argument1, argument2)
在许多情况下,发送消息时不需要括号:
my_method argument1, argument2
但是,括号是避免含糊不清的必要条件。这将引发一个 SyntaxError,因为 ruby 不知道应该发送哪个方法参数3:
method_one argument1, method_two argument2, argument3
如果方法定义有一个*argument
额外的位置参数,则将argument
在方法中将其指定为一个 Array。
如果方法定义不包含关键字参数,则将关键字或散列类型参数指定为最后一个参数的单个散列值:
def my_method(options)
p options
end
my_method('a' => 1, b: 2) # prints: {'a'=>1, :b=>2}
如果提供了太多的位置参数,则会引发一个 ArgumentError。
默认位置参数
当方法定义默认参数时,您不需要为该方法提供所有参数。Ruby 将按顺序填写缺失的参数。
首先,我们将介绍右侧显示默认参数的简单情况。考虑这种方法:
def my_method(a, b, c = 3, d = 4)
p [a, b, c, d]
end
这里c
和d
具有红宝石将适用于你的默认值。如果您仅向此方法发送两个参数:
my_method(1, 2)
你会看到 ruby 打印[1, 2, 3, 4]
。
如果您发送三个参数:
my_method(1, 2, 5)
你会看到 ruby 打印 [1, 2, 5, 4]
Ruby 从左到右填充缺失的参数。
Ruby 允许默认值出现在位置参数的中间。考虑这个更复杂的方法:
def my_method(a, b = 2, c = 3, d)
p [a, b, c, d]
end
这里b
和c
有默认值。如果您仅向此方法发送两个参数:
my_method(1, 4)
你会看到 ruby 打印[1, 2, 3, 4]
。
如果您发送三个参数:
my_method(1, 5, 6)
你会看到 ruby 打印[1, 5, 3, 6]
。
用文字描述这一点变得复杂和令人困惑。我会用变量和值来描述它。
首先1
分配给a
,然后6
分配给d
。这只保留具有默认值的参数。由于5
尚未分配给值,因此它被赋予b
并c
使用其默认值3
。
关键字参数
关键字参数遵循任何位置参数,并以逗号分隔,如位置参数:
my_method(positional1, keyword1: value1, keyword2: value2)
任何未提供的关键字参数都将使用方法定义中的默认值。如果给出关键字参数,该方法未列出,则会引发 ArgumentError。
块参数
block 参数从调用范围向方法发送闭包。
将消息发送给方法时,块参数总是最后一个。一个块使用do ... end
或发送给一个方法{ ... }
:
my_method do
# ...
end
或者:
my_method {
# ...
}
do end
优先级低于{ }
:
method_1 method_2 {
# ...
}
在以下情况下发送块method_2
:
method_1 method_2 do
# ...
end
发送块到method_1
。请注意,在第一种情况下,如果使用圆括号,块将被发送到method_1
。
块将接受来自发送方法的参数。参数的定义类似于方法定义参数的方式。该块的参数进入| ... |
开放do
或{
:
my_method do |argument1, argument2|
# ...
end
阻止本地参数
您也可以;
在块参数列表中声明块本地参数。分配给块本地参数不会覆盖调用程序范围内块的局部参数:
def my_method
yield self
end
place = "world"
my_method do |obj; place|
place = "block"
puts "hello #{obj} this is #{place}"
end
puts "place is: #{place}"
这打印:
hello main this is block
place is world
因此,place
块中的变量与块place
外部的变量不同。; place
从块参数中移除可以得到如下结果:
hello main this is block
place is block
数组到参数的转换
给定以下方法:
def my_method(argument1, argument2, argument3)
end
您可以使用*
(或 splat)运算符将数组转换为参数列表:
arguments = [1, 2, 3]
my_method(*arguments)
或者:
arguments = [2, 3]
my_method(1, *arguments)
两者相当于:
my_method(1, 2, 3)
如果方法接受关键字参数,则 splat 运算符会将数组末尾的散列转换为关键字参数:
def my_method(a, b, c: 3)
end
arguments = [1, 2, { c: 4 }]
my_method(*arguments)
您也可以使用**
(描述的下一个)将 Hash 转换为关键字参数。
如果数组中的对象数量与该方法的参数数量不匹配,则会引发 ArgumentError。
如果 splat 操作员在呼叫中首先出现,则必须使用括号来避免警告。
散列到关键字参数转换
给定以下方法:
def my_method(first: 1, second: 2, third: 3)
end
您可以使用**
运算符将一个 Hash 转换为关键字参数:
arguments = { first: 3, second: 4, third: 5 }
my_method(**arguments)
或者:
arguments = { first: 3, second: 4 }
my_method(third: 5, **arguments)
两者相当于:
my_method(first: 3, second: 4, third: 5)
如果方法定义用于**
收集任意关键字参数,则不会通过以下方式收集它们*
:
def my_method(*a, **kw)
p arguments: a, keywords: kw
end
my_method(1, 2, '3' => 4, five: 6)
打印:
{:arguments=>[1, 2, {"3"=>4}], :keywords=>{:five=>6}}
与上面描述的 splat 操作符不同,**
操作员没有公认的名称。
Proc 阻止转换
给定一个使用块的方法:
def my_method
yield self
end
您可以使用&
运算符将 proc 或 lambda 转换为块参数:
argument = proc { |a| puts "#{a.inspect} was yielded" }
my_method(&argument)
如果图示运算符在调用中首先出现,则必须使用括号来避免警告。
与上面描述的 splat 操作符不同,&
操作员没有公认的名称。
方法查找
当您发送消息时,Ruby 会查找与接收者的消息名称相匹配的方法。方法存储在类和模块中,所以方法查找可以走这些,而不是对象本身。
以下是接收方类或模块的方法查找顺序R
:
- 相反顺序的前置模块
R
- 对于
R
中的匹配方法
- 所包含的模块
R
以相反的顺序排列
如果R
是具有超类的类,则R
直到找到一个方法才会重复此类。
一旦找到匹配,方法查找停止。
如果没有发现匹配,这从一开始就重复,但寻找method_missing
。缺省值method_missing
是 BasicObject#method_missing
,它在调用时引发 NameError。
如果细化(实验性功能)处于活动状态,则方法查找会更改。有关详细信息,请参阅优化文档。