## 9.功能
當你多次使用同一段代碼時,可以將它們分組為一個函數,你可以在程序中的任何位置調用該分組代碼以執行特定任務。 讓我們以一個現實世界為例,你去旅館,侍者走近,你點了一份炸魚,就明白了。 訂購后,你不會受到任何影響。
一旦訂購了魚苗,就會發生很多程序。 服務員記下你的訂單,他去廚房,將訂單交給廚師,廚師告訴他要煮熟的菜肴會花費很多時間。 服務員想著如何避免讓你感到無聊,他來到你的餐桌旁,為你推薦開胃菜和/或開胃菜,為你提供可以在吃菜前喝得很好的飲料,他匯集了廚房以查看菜是否 準備好了。 如果菜已經準備好并且你已經完成了開胃菜,那么他將為你服務。 如果你還沒吃完開胃菜,他會告訴廚房讓菜保溫,然后等你煮完。 一旦他把盤子拿到你的桌子上,他就放下裝有盤子和餐具的盤子。
你要做的只是訂購炸魚,而完全忽略了后臺正在運行的功能。 你向服務員下了訂單(輸入),然后拿到了盤子(輸出)。 根據服務員的訓練,服務員會預先計劃或訓練做什么和不做什么。
讓我們開始使用 Ruby 中的函數。 我們將看一個程序,其中將編寫一個名為`print_line`的函數,該函數將打印一行。 在文本編輯器中鍵入以下程序并運行它。
```rb
# function.rb
def print_line
puts '_'*20
end
print_line
puts "This program prints lines"
print_line
```
輸出量
```rb
____________________
This program prints lines
____________________
```
讓我們分析程序。 考慮以下代碼:
```rb
def print_line
puts '_'*20
end
```
`def`告訴你正在定義一個功能。 函數必須具有名稱,該名稱緊隨`def`關鍵字之后。 在這種情況下,函數的名稱為`print_line`。 你可以在其中編寫所需的代碼。 在這種情況下,我們將創建一個包含 20 個下劃線字符的行。
因此,我們創建了一個函數,并向其中添加了代碼。 現在我們需要做的就是從程序中調用該函數。 只需在程序中鍵入函數名稱即可,如下所示
```rb
print_line
puts "This program prints lines"
print_line
```
從輸出中可以看到,在字符串`“This program prints lines”`的上方和下方都打印了由 20 個下劃線字符組成的行。
### 9.1。 參數傳遞
讓我們對本節中的功能進行更多控制。 有時你不去酒店訂購一頓菜,你可以訂購多少或更少。 如果你和朋友一起去,可以訂購更多份量;如果你一個人,則訂購的份量會更少。 為什么用`print_line`功能不能做同樣的事情? 為什么我們不能更改其長度,這樣做將是一件很了不起的事情,我們可以根據自己的選擇打印長度的行。
看下面的代碼,我們在函數名稱后鍵入了一個名為`length`的東西,它稱為參數。 像函數一樣,參數也有一個名稱,在這種情況下,我們將其命名為`length`。 我們可以將任何值傳遞給它以改變打印行的`length`。 輸入以下代碼并執行
```rb
# function_1.rb
def print_line length
puts '_'*length
end
10.step(50,10) do |x|
print_line x
end
40.step(10,-10) do |x|
print_line x
end
```
你將獲得如下所示的設計模式
```rb
__________
____________________
______________________________
________________________________________
__________________________________________________
________________________________________
______________________________
____________________
__________
```
看下面的代碼
```rb
10.step(50,10) do |x|
print_line x
end
40.step(10,-10) do |x|
print_line x
end
```
我們已經使用`step`循環將捕獲的值遞增或遞減到循環內的`x`變量中,通過將`x`傳遞給`print_line`函數,方法是將其放置在調用后,如上突出顯示 。 因此,每次打印一條不同長度的線(由`x`決定)。 以某種方式構造程序,以便生成模式。
### 9.2。 默認參數
在 [function_1.rb](code/function_1.rb) 中,你了解了如何將參數傳遞給函數。 如果假設你無法通過辯論,該怎么辦? 如果這樣做,將會產生一個錯誤,一個好的程序員將不會希望發生這種錯誤。 為了防止這種情況并使編程變得容易一些,最好為函數提供默認參數。 注意下面在 [function_default_argument.rb](code/function_default_argument.rb) 中給出的代碼
```rb
# function_default_argument.rb
def print_line length = 20
puts '_'*length
end
print_line
print_line 40
```
執行程序并觀察結果
```rb
____________________
________________________________________
```
你可以在程序中通過輸入`length = 20`來查看函數`print_line`,這表明如果未傳遞任何參數,則該函數必須假定`length`的值為 20。 如果通過,則此值將被你傳遞的任何值所覆蓋。 正如你在第一個函數調用中看到的那樣,我們僅通過函數名稱`print_line`來調用函數,我們無需理會將長度值傳遞給它,但是我們看到在輸出中打印出一行長度為 20 個單位的行 。
### 9.3。 將數組傳遞給函數
通常,當你將變量傳遞給函數時,會創建該變量的副本。 而且,如果你對變量進行了更改,則該函數外部的變量不會受到影響。 因此,讓我們看看將數組傳遞給函數時會發生什么。 在下面的程序中鍵入并運行它。
```rb
# array_passed_to_function.rb
def array_changer array
array << 6
end
some_array = [1, 2, 3, 4, 5]
p some_array
array_changer some_array
p some_array
```
Output
```rb
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
```
如果你是編程新手,這可能并不奇怪,但是當將變量傳遞給函數時,其值不應更改。 但是在數組的情況下,在函數`array_changer`中,我們向其中添加了一個元素,并且它會更改。 好吧,這是數組傳遞給函數的特殊行為。
為避免這種情況,請嘗試以下程序
```rb
# array_copy.rb
def array_changer array
array << 6
end
some_array = [1, 2, 3, 4, 5]
p some_array
array_changer Marshal.load(Marshal.dump(some_array))
p some_array
```
Output
```rb
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
```
在這里,數組沒有改變,請看`array_changer Marshal.load(Marshal.dump(some_array))`行,這段代碼將`some_array`復制到 function 參數,以便即使在函數內部對其進行了更改,也不會在函數外部進行更改。
////在這里寫函數式編程
### 9.4。 返回值
到目前為止,我們已經看到函數接受了參數,現在我們看到函數可以返回可用于某些目的的值。 現在讓我們來看程序 [function_return.rb](/code/function_return.rb) ,研究代碼,鍵入并執行它。
```rb
#! /usr/bin/ruby
# function_return.rb
def addition x, y
sum = x+y
return sum
end
a, b = 3, 5
puts addition a,b
```
Output
```rb
8
```
執行后得到的輸出為 8。請注意上述程序中名為 addition 的方法。 它接受兩個參數`x`和`y`,在該方法內部,我們聲明一個名為`sum`的變量,該變量分配給`x`與`y`的加法。 下一個語句是此處的主人公,請參見我們使用了關鍵字`return`,這將返回該函數的值。 在上面的程序中,我們返回`sum`,因此當我們得到答案時。
不是我們必須使用`return`語句返回值。 默認情況下,返回在 Ruby 函數中執行的最后一條語句。 考慮下面顯示的程序 [function_last_gets_returned.rb](code/function_last_gets_returned.rb) 。 在其中,我們有一個名為`square_it`的方法,該方法接受一個名為`x`的單個參數。 它只有一個語句`x**2`,恰好也是最后一個語句。
```rb
#!/usr/bin/ruby
# function_last_gets_returned.rb
def square_it x
x**2
end
puts square_it 5
```
輸入程序并執行。
```rb
25
```
如你所見,我們調用了`square_it 5`,結果為 25。 這可能是因為在 Ruby 中,默認情況下返回上一次執行的語句的結果。
### 9.5。 關鍵字參數
要了解關鍵字參數,請在下面鍵入程序并執行:
```rb
# keyword_argument.rb
def say_hello name: "Martin", age: 33
puts "Hello #{name} your age is #{age}"
end
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
say_hello
```
Output
```rb
Hello Joseph your age is 7
Hello Vignesh your age is 21
Hello Martin your age is 33
```
因此,要查看此功能的工作原理,請分析代碼。 查看 say_hello 的函數定義,如下所示
```rb
def say_hello name: "Martin", age: 33
puts "Hello #{name} your age is #{age}"
end
```
查看突出顯示的部分`def say_hello name: "Martin", age: 33`。 在這里,我們不將參數指定為`def say_hello name= "Martin", age= 33`,而是使用特殊的`name: “Martin”`,我們取出了等號并替換為冒號。 那有什么用呢? 現在看一下函數調用的部分
```rb
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
say_hello
```
第一行是`say_hello name: "Joseph", age: 7`,此處第一個參數是`name`,第二個參數是`age`。 但是看看代碼`say_hello age: 21, name: "Vignesh"`,這里的第一個參數是`age`,第二個參數是`name`。 但是由于參數是由關鍵字提示的,因此它的位置無關緊要,并且該方法將按預期輸出字符串。
第三行`say_hello`只是顯示如果缺少參數會發生什么,因為我們已經指定了默認值,所以它采用了默認值。 是否可以將關鍵字參數與默認值一起使用? 絕對沒錯。 試試下面的程序,看看自己
```rb
# keyword_argument_no_defaults.rb
def say_hello name:, age:
puts "Hello #{name} your age is #{age}"
end
say_hello name: "Joseph", age: 7
say_hello age: 21, name: "Vignesh"
# say_hello # uncomment it and try it out
# say_hello "Karthik", 32 # uncomment it and try it out
```
### 9.6。 遞歸函數
讓我們看看另一件事。 你可能想知道為什么我要進行所有數學運算? 某些程序員確實寫了一些書,這些書盡可能地排除了數學知識,我不是專業的數學家,但我很欣賞數學。 計算機是基于數學的。 所有計算機都使用稱為布爾代數的東西來執行所有任務。 我并不是說你必須是數學家才能成為程序員,但是了解數學確實會有所幫助。
好,什么是階乘? 取一個數字,取 3,現在將是 3 X 2 X 1,即六個! 是不是很簡單? 6 是 3 的階乘。好吧,我們現在取 4,所以 4 X 3 X 2 X 1 將是 24,以類似的方式,2 的階乘將是 2 X 1,即 2。有了這些知識,我們現在將構造一個 該程序將為我們提供一定數量的階乘。
研究下面給出的程序。 專注于名為階乘的函數
```rb
# factorial.rb
def factorial num
fact = 1
1.upto(num) { |a|
fact = fact * a
}
fact
end
number = 17
puts "Factorial of #{number} = #{factorial number}"
```
執行上面的代碼,這就是你得到的輸出
```rb
Factorial of 17 = 355687428096000
```
在上面的示例中(在階乘函數中),我們將所有數字從一個取到特定的數字,將其相乘得到階乘。 現在研究如下所示的代碼 [factorial_1.rb](code/factorial_1.rb)
```rb
# factorial_1.rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
number = 17
puts "Factorial of #{number} = #{factorial number}"
```
Execute the code above and this is what you get as output
```rb
Factorial of 17 = 355687428096000
```
輸出與先前程序 [factorial.rb](code:factorial.rb) 相同。 請仔細查看上述程序中名為`factorial`的功能。 我列出來看看
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
該功能令人困惑,不是嗎? 當我發瘋并且想學習編程時,我學習了 C。遞歸函數的概念是使用階乘解釋的,而且我很長一段時間都沒有理解它。 為了避免痛苦,讓我詳細解釋。
取數字 1。它的階乘為 1。因此,如果遇到 1,則返回 1,如下代碼所示
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
現在考慮數字 2 的階乘 2 X 1,它是 2 乘以 1 的階乘。換句話說,我們可以將其寫為 2 乘以 2-1 的階乘。 因此,如果在函數`factorial`中遇到第二個數字,它將跳過第一個 if 語句,而下面的第二個語句`return num * factorial(num-1)`被執行
```rb
def factorial num
return 1 if num == 1
return num * factorial(num-1)
end
```
在這個有趣的事情發生了。 這里調用階乘(2-1),即階乘函數本身。 因此,當 2-1 的階乘,即 1 的階乘被調用時,它返回 1,該 1 乘以 2 并返回,因此在這種情況下最終返回 2。
現在取數字 3。其階乘為 3 X 2 X1。這可以寫成 3 乘以階乘 2。階乘 2 轉換為 2 乘以階乘 1。因此最終得到結果。 對于任何大于 1 的數字,階乘函數都會反復調用其自身。 函數調用本身的過程稱為遞歸。
### 9.7。 可變數量的參數
假設你不知道向一個函數傳遞了多少個參數,假設你正在編寫一個要添加 N 個數字的函數,則 N 的值未知,那么如何獲得可變數量的參數。 鍵入下面給出的程序 [function_variable_arguments.rb](code/function_variable_arguments.rb) 并執行它。
```rb
# function_variable_arguments.rb
def some_function a, *others
puts a
puts "Others are:"
for x in others
puts x
end
end
some_function 1,2,3,4,5
```
Output
```rb
1
Others are:
2
3
4
5
```
因此,程序的輸出如上所示。 如你所見,我們將 1,2,3,4,5 作為參數傳遞,那么`a`只是一個變量,因此它取值為 1,其他變量被變量`**others**` **吸收( 注意,變量名前的星號** 是一種特殊的自變量,它將所有未被前一個自變量吸收的其余自變量存儲在其他變量名中(作為數組)。 現在在下面的代碼中
```rb
for x in others
puts x
end
```
就是這樣。 現在嘗試編寫一個函數以查找 n 個數的最大值,并編寫另一個函數以查找 n 個數的最小值,并編寫一個程序查找一堆數字的最大值和最小值。
### 9.8。 哈希作為函數參數
潛入多個參數到函數中的另一種方法是將它們作為哈希傳遞。 看下面的程序,我們有一個名為`some_function`的函數,該函數有兩個參數,第一個名為`first_arg`,第二個名為`others_as_hash`,我們在下一行`some_function "Yoda", {jedi: 100, sword: 100, seeing_future: 100}`中調用此函數,執行它并 注意輸出
```rb
# hashes_to_functions.rb
def some_function first_arg, others_as_hash
puts "Your first argument is: #{first_arg}"
puts "Other arguments are:"
p others_as_hash
end
some_function "Yoda", {jedi: 100, sword: 100, seeing_future: 100}
```
Output
```rb
Your first argument is: Yoda
Other arguments are:
{:jedi=>100, :sword=>100, :seeing_future=>100}
```
如我們所料,程序將打印第一個參數并傳遞給`others_as_hash`的哈希,這并不奇怪,但請看下面的程序 [hashes_to_function_1.rb](code/hashes_to_function_1.rb) ,執行該程序,其輸出將 與上面的程序相同
```rb
# hashes_to_functions_1.rb
def some_function first_arg, others_as_hash
puts "Your first argument is: #{first_arg}"
puts "Other arguments are:"
p others_as_hash
end
some_function "Yoda", jedi: 100, sword: 100, seeing_future: 100
```
但是請注意這部分,我們已經將`some_function`稱為
```rb
some_function "Yoda", jedi: 100, sword: 100, seeing_future: 100
```
在函數中,我們將第二個參數作為哈希值進行傳遞,但是如上所示,它應予注意,請注意,我們已避免使用花括號,并且它仍然有效。 這才是重點。
- 前言
- 紅寶石
- 先決條件
- 1.安裝 Ruby
- 2.在線資源
- 3.入門
- 4.比較與邏輯
- 5.循環
- 6.數組
- 7.哈希和符號
- 8.范圍
- 9.功能
- 10.可變范圍
- 11.類&對象
- 12.安全導航
- 13.打破大型程序
- 14.結構和 OpenStruct
- 15. Rdoc
- 16. Ruby 樣式指南
- 17.模塊和混入
- 18.日期和時間
- 19.文件
- 20. Proc,Lambda 和塊
- 21.多線程
- 22.異常處理
- 23.正則表達式
- 24.寶石
- 25.元編程
- 26.基準
- 27.測試驅動開發
- 28.觀察者模式
- 29.模板模式
- 30.工廠模式
- 31.裝飾圖案
- 32.適配器模式
- 33.單例模式
- 34.復合模式
- 35.建造者模式
- 36.策略模式
- 贊助商
- 捐
- 人們怎么說
- 版權
- 取得這本書