呼叫方法

呼叫方法會將訊息傳送給物件,以便執行一些工作。

在 Ruby 中,您可以像這樣傳送訊息給物件

my_method()

請注意,括號是可選的

my_method

除了使用和省略括號之間有差異的情況外,本文檔在有參數時使用括號,以避免混淆。

此區段僅涵蓋呼叫方法。另請參閱定義方法的語法文件

接收者

self 是預設接收者。如果您未指定任何接收者,將使用 self。若要指定接收者,請使用 .

my_object.my_method

這會將 my_method 訊息傳送至 my_object。任何物件都可以是接收者,但根據方法的可見性,傳送訊息可能會引發 NoMethodError

您也可以使用 :: 指定接收者,但由於與命名空間的 :: 容易混淆,因此很少使用。

串連方法呼叫

您可以透過緊接一個方法呼叫後再呼叫另一個方法來「串連」方法呼叫。

此範例串連方法 Array#appendArray#compact

a = [:foo, 'bar', 2]
a1 = [:baz, nil, :bam, nil]
a2 = a.append(*a1).compact
a2 # => [:foo, "bar", 2, :baz, :bam]

詳細資料

您可以串連不同類別中的方法。此範例串連方法 Hash#to_aArray#reverse

h = {foo: 0, bar: 1, baz: 2}
h.to_a.reverse # => [[:baz, 2], [:bar, 1], [:foo, 0]]

詳細資料

安全導覽運算子

&.,稱為「安全導覽運算子」,允許在接收者為 nil 時略過方法呼叫。如果略過呼叫,它會傳回 nil,且不會評估方法的參數。

REGEX = /(ruby) is (\w+)/i
"Ruby is awesome!".match(REGEX).values_at(1, 2)
# => ["Ruby", "awesome"]
"Python is fascinating!".match(REGEX).values_at(1, 2)
# NoMethodError: undefined method `values_at' for nil:NilClass
"Python is fascinating!".match(REGEX)&.values_at(1, 2)
# => nil

這允許輕鬆串連可能會傳回空值的方法。請注意,&. 僅略過下一個呼叫,因此對於較長的串連,需要在每個層級新增運算子

"Python is fascinating!".match(REGEX)&.values_at(1, 2).join(' - ')
# NoMethodError: undefined method `join' for nil:NilClass
"Python is fascinating!".match(REGEX)&.values_at(1, 2)&.join(' - ')
# => nil

參數

傳送訊息時有三種類型的參數,位置參數、關鍵字(或命名)參數和區塊參數。每個傳送的訊息都可以使用一種、兩種或所有類型的參數,但參數必須按此順序提供。

Ruby 中的所有參數都是按引用傳遞的,並且不會延遲評估。

每個參數都以 , 分隔。

my_method(1, '2', :three)

參數可以是表達式、hash 參數

'key' => value

或關鍵字參數

key: value

Hash 和關鍵字參數必須是連續的,並且必須出現在所有位置參數之後,但可以混合使用

my_method('a' => 1, b: 2, 'c' => 3)

位置參數

訊息的位置參數跟在方法名稱之後

my_method(argument1, argument2)

在許多情況下,傳送訊息時不需要括號

my_method argument1, argument2

但是,為了避免歧義,括號是必要的。這將會引發 SyntaxError,因為 Ruby 不知道應該將哪個方法 argument3 傳送給

method_one argument1, method_two argument2, argument3

如果方法定義有 *argument,則額外的位置參數將會在方法中指定給 argument 作為 Array

如果方法定義不包含關鍵字參數,則關鍵字或 hash 類型的參數將指定為單一 hash 給最後一個參數

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 有 Ruby 會為您套用的預設值。如果您只傳送兩個參數給這個方法

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 尚未指定給值,因此它會給予 b,而 c 使用其預設值 3

關鍵字參數

關鍵字參數遵循任何位置參數,並以逗號分隔,就像位置參數一樣

my_method(positional1, keyword1: value1, keyword2: value2)

任何未給定的關鍵字參數將使用來自方法定義的預設值。如果給定方法未列出的關鍵字參數,且方法定義不接受任意關鍵字參數,則會引發 ArgumentError

可以省略關鍵字參數值,表示將透過金鑰名稱從內容中擷取值

keyword1 = 'some value'
my_method(positional1, keyword1:)
# ...is the same as
my_method(positional1, keyword1: keyword1)

請注意,當省略方法括號時,解析順序可能會出乎意料

my_method positional1, keyword1:

some_other_expression

# ...is actually parsed as
my_method(positional1, keyword1: some_other_expression)

區塊參數

區塊參數會將封閉從呼叫範圍傳送至方法。

傳送訊息至方法時,區塊參數總是最後一個。使用 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

Array 轉換為參數

給定以下方法

def my_method(argument1, argument2, argument3)
end

您可以使用 *(或展開)運算子將 Array 轉換為參數清單

arguments = [1, 2, 3]
my_method(*arguments)

arguments = [2, 3]
my_method(1, *arguments)

兩者等同於

my_method(1, 2, 3)

您也可以使用 **(在下一段中描述)將 Hash 轉換為關鍵字參數。

如果 Array 中的物件數量與方法的參數數量不符,將會引發 ArgumentError

如果展開運算子在呼叫中排在第一位,則必須使用括號來避免警告

my_method *arguments  # warning
my_method(*arguments) # no warning

Hash 轉換為關鍵字參數

給定以下方法

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], :keywords=>{'3'=>4, :five=>6}}

Proc 轉換為區塊

給定使用區塊的方法

def my_method
  yield self
end

您可以使用 &(區塊轉換)運算子將程序或 lambda 轉換為區塊參數

argument = proc { |a| puts "#{a.inspect} was yielded" }

my_method(&argument)

如果區塊轉換運算子在呼叫中排在第一位,則必須使用括號來避免警告

my_method &argument  # warning
my_method(&argument) # no warning

Method 查詢

當您傳送訊息時,Ruby 會尋找與接收者的訊息名稱相符的方法。方法儲存在類別和模組中,因此方法查詢會遍歷這些類別和模組,而不是物件本身。

以下是接收者的類別或模組 R 的方法查詢順序

如果 R 是具有超類別的類別,則會重複此步驟,使用 R 的超類別,直到找到方法。

一旦找到匹配,方法查詢就會停止。

如果找不到匹配,則會從頭開始重複此步驟,但尋找 method_missing。預設的 method_missingBasicObject#method_missing,它在呼叫時會引發 NameError

如果改良(實驗性功能)處於啟用狀態,方法查詢就會變更。有關詳細資訊,請參閱 改良文件