Ruby 2.4

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

这里cd具有红宝石将适用于你的默认值。如果您仅向此方法发送两个参数:

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

这里bc有默认值。如果您仅向此方法发送两个参数:

my_method(1, 4)

你会看到 ruby 打印[1, 2, 3, 4]

如果您发送三个参数:

my_method(1, 5, 6)

你会看到 ruby 打印[1, 5, 3, 6]

用文字描述这一点变得复杂和令人困惑。我会用变量和值来描述它。

首先1分配给a,然后6分配给d。这只保留具有默认值的参数。由于5尚未分配给值,因此它被赋予bc使用其默认值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。

如果细化(实验性功能)处于活动状态,则方法查找会更改。有关详细信息,请参阅优化文档。