- F# 基礎教程
- F# - 首頁
- F# - 概述
- F# - 環境設定
- F# - 程式結構
- F# - 基本語法
- F# - 資料型別
- F# - 變數
- F# - 運算子
- F# - 決策
- F# - 迴圈
- F# - 函式
- F# - 字串
- F# - 可選項
- F# - 元組
- F# - 記錄
- F# - 列表
- F# - 序列
- F# - 集合
- F# - 對映
- F# - 辨析聯合
- F# - 可變資料
- F# - 陣列
- F# - 可變列表
- F# - 可變字典
- F# - 基本 I/O
- F# - 泛型
- F# - 委託
- F# - 列舉
- F# - 模式匹配
- F# - 異常處理
- F# - 類
- F# - 結構體
- F# - 運算子過載
- F# - 繼承
- F# - 介面
- F# - 事件
- F# - 模組
- F# - 名稱空間
F# - 函式
在 F# 中,函式就像資料型別一樣。你可以像使用其他變數一樣宣告和使用函式。
由於函式可以像其他變數一樣使用,因此您可以:
- 建立一個函式,併為其命名並將其名稱與型別關聯。
- 為其賦值。
- 對該值執行一些計算。
- 將其作為引數傳遞給另一個函式或子例程。
- 將函式作為另一個函式的結果返回。
定義函式
函式使用 **let** 關鍵字定義。函式定義具有以下語法:
let [inline] function-name parameter-list [ : return-type ] = function-body
其中:
**函式名** 是表示函式的識別符號。
**引數列表** 給出由空格分隔的引數列表。您還可以為每個引數指定顯式型別,如果未指定,編譯器會從函式體中推斷出來(如變數)。
**函式體** 由表示式或由多個表示式組成的複合表示式組成。函式體中的最後一個表示式是返回值。
**返回型別** 是冒號後跟一個型別,並且是可選的。如果未指定返回型別,則編譯器會從函式體中的最後一個表示式確定它。
函式的引數
您在函式名後列出引數名。您可以指定引數的型別。引數的型別應該跟在引數名後面,用冒號分隔。
如果未指定引數型別,則由編譯器推斷。
例如:
let doubleIt (x : int) = 2 * x
呼叫函式
透過指定函式名,然後是一個空格,然後是任何用空格分隔的引數來呼叫函式。
例如:
let vol = cylinderVolume 3.0 5.0
以下程式說明了這些概念。
示例 1
以下程式在給定半徑和長度作為引數時計算圓柱體的體積
// the function calculates the volume of // a cylinder with radius and length as parameters let cylinderVolume radius length : float = // function body let pi = 3.14159 length * pi * radius * radius let vol = cylinderVolume 3.0 5.0 printfn " Volume: %g " vol
編譯並執行程式後,將產生以下輸出:
Volume: 141.372
示例 2
以下程式返回兩個給定引數中較大的值:
// the function returns the larger value between two
// arguments
let max num1 num2 : int32 =
// function body
if(num1>num2)then
num1
else
num2
let res = max 39 52
printfn " Max Value: %d " res
編譯並執行程式後,將產生以下輸出:
Max Value: 52
示例 3
let doubleIt (x : int) = 2 * x printfn "Double 19: %d" ( doubleIt(19))
編譯並執行程式後,將產生以下輸出:
Double 19: 38
遞迴函式
遞迴函式是呼叫自身的函式。
您可以使用 **let rec** 關鍵字組合定義遞迴。
定義遞迴函式的語法為:
//Recursive function definition let rec function-name parameter-list = recursive-function-body
例如:
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
示例 1
以下程式返回斐波那契數列 1 到 10:
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2) for i = 1 to 10 do printfn "Fibonacci %d: %d" i (fib i)
編譯並執行程式後,將產生以下輸出:
Fibonacci 1: 1 Fibonacci 2: 2 Fibonacci 3: 3 Fibonacci 4: 5 Fibonacci 5: 8 Fibonacci 6: 13 Fibonacci 7: 21 Fibonacci 8: 34 Fibonacci 9: 55 Fibonacci 10: 89
示例 2
以下程式返回 8 的階乘:
open System let rec fact x = if x < 1 then 1 else x * fact (x - 1) Console.WriteLine(fact 8)
編譯並執行程式後,將產生以下輸出:
40320
F# 中的箭頭表示法
F# 使用鏈式箭頭表示法報告函式和值中的資料型別。讓我們以一個接受一個 *int* 輸入並返回一個字串的函式為例。在箭頭表示法中,它寫成:
int -> string
資料型別從左到右讀取。
讓我們再舉一個假設的函式的例子,它接受兩個 int 資料輸入並返回一個字串。
let mydivfunction x y = (x / y).ToString();;
F# 使用鏈式箭頭表示法報告資料型別為:
val mydivfunction : x:int -> y:int -> string
返回型別由鏈式箭頭表示法中最右邊的資料型別表示。
更多示例:
| 表示法 | 含義 |
|---|---|
| float → float → float | 該函式接受兩個 *float* 輸入,返回另一個 *float*。 |
| int → string → float | 該函式接受一個 *int* 和一個 *string* 輸入,返回一個 *float*。 |
Lambda 表示式
**Lambda 表示式** 是一個未命名的函式。
讓我們來看兩個函式的例子:
let applyFunction ( f: int -> int -> int) x y = f x y let mul x y = x * y let res = applyFunction mul 5 7 printfn "%d" res
編譯並執行程式後,將產生以下輸出:
35
現在,在上面的例子中,如果我們不定義函式 *mul*,我們可以使用 lambda 表示式:
let applyFunction ( f: int -> int -> int) x y = f x y let res = applyFunction (fun x y -> x * y ) 5 7 printfn "%d" res
編譯並執行程式後,將產生以下輸出:
35
函式組合和管道
在 F# 中,一個函式可以由其他函式組成。
以下示例顯示了從兩個函式 function1 和 function2 組成的名為 f 的函式:
let function1 x = x + 1 let function2 x = x * 5 let f = function1 >> function2 let res = f 10 printfn "%d" res
編譯並執行程式後,將產生以下輸出:
55
F# 還提供了一個稱為 **函式管道** 的功能。管道允許將函式呼叫連結在一起作為連續的操作。
以下示例顯示了:
let function1 x = x + 1 let function2 x = x * 5 let res = 10 |> function1 |> function2 printfn "%d" res
編譯並執行程式後,將產生以下輸出:
55