Rust 入門之函數(shù)和注釋實例詳解
寫在前面
今天我們來學(xué)習(xí) Rust 中的函數(shù),最后會捎帶介紹一下如何在 Rust 中寫注釋。也是比較輕量級的一節(jié),大家快速過一下即可。
函數(shù)
函數(shù)本身是各個語言都支持的類型,我們此前已經(jīng)多次使用 fn main() 這個函數(shù)來承載業(yè)務(wù)邏輯,fn 可以用來聲明一個函數(shù),而 main 函數(shù)跟其他語言一樣,可以理解為程序啟動的【起點】,一切邏輯從這里開始。
Rust 本身的命名規(guī)范是【snake case】,即下劃線 + 小寫,這個其實各個語言都有自己規(guī)范,分清楚環(huán)境即可。
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Another function.");
}
這里的 another_function 就是個沒有入?yún)?,沒有出參的函數(shù),命名遵循 snake case,很好理解。
Rust 中的函數(shù)跟其他語言是一樣的,用 fn 來聲明,后面加上函數(shù)名,小括號里面可以放入?yún)?,之后可以定義出參,最后用花括號來承載函數(shù)體。調(diào)用函數(shù)也不復(fù)雜,函數(shù)名后面跟上小括號+參數(shù)即可,注意 scope 就行,這里是因為我們的 another_function 就在當前包下,所以直接就那來調(diào)用。調(diào)用的時候要保證【函數(shù)所在的 scope 是對 caller 可見】的即可。
我們在 rust-learn 項目下通過 cargo new functions 新建一個項目,試一下上面的代碼:

$ cargo run
===============================
Compiling functions v0.1.0 (/Users/ag9920/go/src/github.com/ag9920/rust-learn/functions)
Finished dev [unoptimized + debuginfo] target(s) in 1.76s
Running `target/debug/functions`
Hello, world!
Another function.
另外需要強調(diào)一點,Rust 文件內(nèi)函數(shù)定義并不要求順序,只要定義在 scope 內(nèi)就能解析,比如 main 函數(shù)先于 another_function 定義是沒問題的。
參數(shù)
還是基于我們此前的 another_function,我們嘗試加一下入?yún)ⅲ纯磻?yīng)該怎么做:
fn main() {
another_function(5);
}
fn another_function(x: i32) {
println!("The value of x is: {x}");
}
執(zhí)行過后,結(jié)果如下:
$ cargo run
===============================
Compiling functions v0.1.0 (/Users/ag9920/go/src/github.com/ag9920/rust-learn/functions)
Finished dev [unoptimized + debuginfo] target(s) in 0.62s
Running `target/debug/functions`
The value of x is: 5
此時 another_function 增加了一個參數(shù) x,我們聲明其類型為 i32。在 main 函數(shù)中調(diào)用的時候,傳入我們的參數(shù) 5,最后被打印出來。
可能有的地方會特意提一下這兩個概念:
- 形參:是在定義函數(shù)時使用的參數(shù),目的是用來接收調(diào)用該函數(shù)時傳進來的實際參數(shù),即 parameter;
- 實參:是在調(diào)用時傳遞給函數(shù)的參數(shù),即 arguments。
但通常說起來的時候我們不太區(qū)分,對我們來說統(tǒng)一叫【參數(shù)】即可。
上面示例中,我們定義入?yún)⑹沁@樣的:fn another_function(x: i32)。
這里【冒號 + 空格 + 類型】的寫法我們已經(jīng)見過很多次了,那能不能不帶類型呢?我直接寫個 fn another_function(x),具體格式留給編譯器來推斷 ok 不?
在 Rust 中這件事是不 ok的,按照規(guī)范,對于每個入?yún)⒛愣急仨毲逦刂该鳌绢愋汀?,這樣編譯器也省事,報錯時也能更精準給出相關(guān)判斷。如果我們需要多個入?yún)?,用【逗號】分隔即可?/p>
fn main() {
print_labeled_measurement(5, 'h');
}
fn print_labeled_measurement(value: i32, unit_label: char) {
println!("The measurement is: {value}{unit_label}");
}
執(zhí)行結(jié)果如下:
$ cargo run
========================
Compiling functions v0.1.0 (/Users/ag9920/go/src/github.com/ag9920/rust-learn/functions)
Finished dev [unoptimized + debuginfo] target(s) in 0.87s
Running `target/debug/functions`
The measurement is: 5h
語句和表達式
Rust 本身是一個基于表達式的語言,所以這兩個概念我們先區(qū)分一下,語句(statements),表達式(expressions)是什么區(qū)別?
Statements are instructions that perform some action and do not return a value. Expressions evaluate to a resulting value.
簡單說,就是看有沒有【返回值】,無返回值的是語句,有返回值的是表達式,表達式可以是一個語句的組成部分。
舉個例子:let y = 6; 這就是一個【語句】,而 6 就是一個【表達式】,在 Rust 中你是不能做 let x = (let y = 6); 這樣的操作的,因為括號里面的部分是個語句,語句沒有返回值,那么該拿什么給 x 賦值呢?
所以,不像其他語言,可能允許類似 x = y = 6,這樣讓 x 和 y 都賦值了 6。Rust 是不允許這樣的。
fn main() {
let y = {
let x = 3;
x + 1
};
println!("The value of y is: {y}");
}
比如上面這個案例,在花括號這個 scope 中,我們定義了 x 變量,將其賦值為 3,然后將 x+1 這個表達式返回,所以 y 被賦值為 4。
花括號里面的部分就是一個表達式,返回了 4 。注意 x + 1 的結(jié)尾沒有分號,這也是表達式的特征。這里千萬不能加分號,要想清楚。如果你想用一個表達式返回,就不加分號。加了之后變成了語句,但也不會返回什么東西。
Rust 函數(shù)體則是由一系列【語句】+ 默認可選的一個【表達式】組成。為什么是可選的?因為類似我們前面的函數(shù),沒有返回值,不需要最后的這個【表達式】。
返回值
Rust 是不支持命名返回值的(這一點跟 Golang 有所不同),函數(shù)定義出參的部分需要用【箭頭符號】顯式地聲明。
不像很多函數(shù)要求顯式的 return 返回值,Rust 默認會返回最后的表達式的值。當然我們?nèi)绻?early return 也是 ok的,但大多數(shù)函數(shù)不會寫 return 這個關(guān)鍵字,而是隱式地返回最后一個表達式。我們來看一個例子:
fn five() -> i32 {
5
}
fn main() {
let x = five();
println!("The value of x is: {x}");
}
這里的 five 函數(shù)非常簡單,只有一個 5 作為表達式返回,不需要 return。
這是完全合法的 Rust 函數(shù),出參只有一個 i32。我們加上入?yún)?,再看一個例子:
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1
}
此時我們有一個 i32 入?yún)?,也有一個 i32 出參,函數(shù)體是一個簡單的表達式 x + 1。運行上面代碼打印的結(jié)果是 The value of x is: 6,符合預(yù)期。
我們試試給 x + 1 后面加上個分號看看:
fn main() {
let x = plus_one(5);
println!("The value of x is: {x}");
}
fn plus_one(x: i32) -> i32 {
x + 1;
}
此時運行結(jié)果果然報錯(這個不是運行時報錯,是編譯階段識別的)
$ cargo run
====================
Compiling functions v0.1.0 (/Users/ag9920/go/src/github.com/ag9920/rust-learn/functions)
error[E0308]: mismatched types
--> src/main.rs:7:24
|
7 | fn plus_one(x: i32) -> i32 {
| -------- ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
8 | x + 1;
| - help: remove this semicolon
For more information about this error, try `rustc --explain E0308`.
error: could not compile `functions` due to previous error
問題在于,plus_one 說了會有返回值 i32,但到最后也沒發(fā)現(xiàn)【表達式】,此時 Rust 默認會返回 () 一個空的 tuple(我們上一節(jié)講過,這個叫 unit),所以報錯叫做【 mismatched types】,而不是類似【no return value】,這里是不是就理解了?
沒有返回值的函數(shù),本質(zhì)上是返回了一個 unit:
// Functions that "don't" return a value, actually return the unit type `()`
fn fizzbuzz(n: u32) -> () {
if is_divisible_by(n, 15) {
println!("fizzbuzz");
} else if is_divisible_by(n, 3) {
println!("fizz");
} else if is_divisible_by(n, 5) {
println!("buzz");
} else {
println!("{}", n);
}
}
問題又來了,那 Rust 能不能支持多個出參呢?類似 Golang 中的:
func addsub(x, y int) (int, int) {
return x + y, x - y
}
其實 Rust 對這個事情的解決方案就是我們已經(jīng)見過多次的 tuple:
fn addsub(x: isize, y: isize) -> (isize, isize) {
(x + y, x - y)
}
fn my_func() -> (u8, bool) {
(1, true)
}
圓括號千萬不能少,記住我們 return 的是個 tuple,不是多個單獨的值。
這里有一個可運行的 online 示例,大家可以復(fù)習(xí)一下 tuple,結(jié)合多個返回值體會一下:
fn swap(x: i32, y: i32) -> (i32, i32) {
return (y, x);
}
fn main() {
// return a tuple of return values
let result = swap(123, 321);
println!("{} {}", result.0, result.1);
// destructure the tuple into two variables names
let (a, b) = swap(result.0, result.1);
println!("{} {}", a, b);
}
注釋
注釋其實比較簡單,我們快速提一下。
Rust 的行注釋就是常見的 // 雙斜杠,如果一行放不下,需要多行的話,也需要在每一行前面加.
fn main() {
// I'm feeling lucky today
let lucky_number = 7;
}
文檔注釋有些許的區(qū)別,這里需要用 /// 三斜杠,這樣能夠輔助生成 HTML 文檔。
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}以上就是Rust 入門之函數(shù)和注釋實例詳解的詳細內(nèi)容,更多關(guān)于Rust 函數(shù)注釋的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Rust-使用dotenvy加載和使用環(huán)境變量的過程詳解
系統(tǒng)的開發(fā),測試和部署離不開環(huán)境變量,今天分享在Rust的系統(tǒng)開發(fā)中,使用dotenvy來讀取和使用環(huán)境變量,感興趣的朋友跟隨小編一起看看吧2023-11-11
Rust語言開發(fā)環(huán)境搭建詳細教程(圖文教程)
本文主要介紹了rust編程語言在windows上開發(fā)環(huán)境的搭建方法,文中通過圖文的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
Rust應(yīng)用調(diào)用C語言動態(tài)庫的操作方法
這篇文章主要介紹了Rust應(yīng)用調(diào)用C語言動態(tài)庫,本文記錄了筆者編寫一個簡單的C語言動態(tài)庫,并通過Rust調(diào)用動態(tài)庫導(dǎo)出的函數(shù),需要的朋友可以參考下2023-01-01
Rust語言從入門到精通之Tokio的Channel深入理解
這篇文章主要為大家介紹了Rust語言從入門到精通之Tokio的Channel深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05

