這部分我們學習 rust 語言的 變量、數據類型、函數、注釋、流程控制
這五個方面的內容。本文我們介紹前兩個內容,下一篇文章介紹后三個內容。
變量
默認情況下,rust 語言中聲明的變量是不可變的,比如如下代碼:
fn main() {
let x = 5;
println!("x 的值是: {}", x);
x = 6;
println!("x 的值是: {}", x);
}
我們先來跑一下這段代碼:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
3 | println!("x 的值是: {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0384`.
通過運行結果,我們發現這段代碼有問題的,然后我們從報錯信息中抓取關鍵信息: cannot assign twice to immutable variable
,它的意思是 不可變變量不能進行二次賦值
。但是有些時候,我們也需要修改變量的值,應該怎么辦呢,在變量名的前面,let 關鍵字的后面添加一個關鍵字 mut 就行了,我們來試試:
fn main() {
let mut x = 5;
println!("x 的值是: {}", x);
x = 6;
println!("x 的值是: {}", x);
}
運行一下代碼:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 3.53s
Running `target/debug/hello_cargo`
x 的值是: 5
x 的值是: 6
這種不可變變量的設計有着很多安全方面的考慮,這里不再贅述。談到這里,很容易聯想到編程語言的另一個概念——常量,那二者有什么區別呢?
1.常量不能使用 mut 關鍵字修飾,常量在任何情況下都是不可變的(變量是在默認情況下不可變)。
2.常量使用 const 關鍵字來聲明,而變量使用 let 關鍵字來聲明。
3.常量需要在常量名后面緊跟冒號和類型,例如 const MAX_POINTS: u32 = 100_000;
,而變量可以省略冒號和類型的修飾。
4.常量的作用域是任何作用域,包括全局作用域。
5.常量只能使用常量表達式賦值,而不能使用函數結果或者其它運行時產生的值。
注:這是說明一下,常量通常使用大寫字母和下划線 _ 來命名。
我們再來說一個變量的特性——覆蓋。在上一篇寫猜數字游戲的文章中,我們做數字類型轉換的時候,新類型的名字使用了舊類型的名字,這種情況就是覆蓋。先來個實例:
fn main() {
let x = 5;
println!("x 的值是: {}", x);
let x = 6;
println!("x 的值是: {}", x);
}
我們來看運行結果:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/hello_cargo`
x 的值是: 5
x 的值是: 6
通過結果可以發現,第二個使用 let 關鍵字修飾的不可變變量 x 把第一個 x 覆蓋了,也就是說把 x 的值從 5 改成了 6。那這和 mut 有什么區別呢?
1.覆蓋的第二個變量需要使用 let 關鍵字修飾,如果沒有 let 關鍵字,則會報錯。
2.覆蓋的第二個變量不僅可以改變值,還可以修改變量的類型;而 mut 不可以改變類型。
這里舉兩個例子來說明第二個區別:
fn main() {
let space = "abc";
println!("space 代表的是:{}", space);
let space = space.len();
println!("space 代表的是:{}", space);
}
先來運行第一個例子:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.22s
Running `target/debug/hello_cargo`
space 代表的是:abc
space 代表的是:3
然后看第二個例子:
fn main() {
let mut space = "abc";
println!("space 代表的是:{}", space);
space = space.len();
println!("space 代表的是:{}", space);
}
跑一下第二個例子:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
error[E0308]: mismatched types
--> src/main.rs:4:13
|
4 | space = space.len();
| ^^^^^^^^^^^ expected &str, found usize
|
= note: expected type `&str`
found type `usize`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
error: could not compile `hello_cargo`.
To learn more, run the command again with --verbose.
可以輕易看到二者的區別,好了,接下來我們看 rust 的基本類型。
數據類型
rust 的數據類型就是在編譯期間告訴 rust 的編譯器如何處理這些數據。在這里,我們會了解到兩種數據類型:基本數據類型和組合數據類型。
基本數據類型
基本數據類型也就是簡單值,rust 主要包含了 4 種基本數據類型,分別是整型、浮點型、布爾型和字符型。你可能在其他語言中見過這些類型,現在,我們來看一下它們在 rust 語言中是怎么樣的。
整型
整型是不包含小數的數字類型。整型包含了兩種類型:i 打頭的有符號整型和 u 打頭的無符號整型。我們使用一個表格來描述 rust 的整型:
占用空間 | 有符號整型 | 無符號整型 |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
格式 | i+長度 | u+長度 |
整型在使用過程中默認類型是 i32。
浮點型
浮點型包含了兩種類型:單精度浮點型 f32,雙精度浮點型 f64。浮點型在使用過程中默認類型是 f64。
數據操作
rust 支持的基本數據操作有:加 +,減 -,乘 *,除 /,取模 %。
布爾型
布爾型通常有兩個值:true和false。它占用 1 個字節,使用 bool 關鍵字來聲明。
字符型
rust 的字符類型占用 4 個字節,它的值是使用單引號 '
引起來的。
組合數據類型
組合數據類型是把多個值組合成一個類型。在 rust 中,組合數據類型有兩種:元組和數組。
元組
元組是把多個基本類型組合成一個組合類型。它有一個確定的長度,一旦確定就不能再次加減元素了。我們先來看一個元組的實例:
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("第0個值:{}, 第1個值:{}, 第2個值:{}", tup.0, tup.1, tup.2);
let (x, y, z) = tup;
println!("x的值:{}, y的值:{}, z的值:{}", x, y, z);
}
它運行的結果是:
cargo run
Compiling hello_cargo v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/hello_cargo`
第0個值:500, 第1個值:6.4, 第2個值:1
x的值:500, y的值:6.4, z的值:1
元組的取值有兩種方式,一種是把元組解構成多個變量,另一種就是使用 .
的方式,順序是從 0 開始。
數組
數組和元組不一樣的地方是:數組只能使用相同的數據類型。數組和元組相同的地方是:長度一旦確定就不能加減元素了。如果想改變數組的長度,可以使用 vector 類型,后續文章會介紹 vector 類型的情況。而且數組還有一個特性,它會把數據分配到棧內存,而不是堆內存。下面舉幾個常用的數組的例子:
fn main() {
// 定義一個簡單的數組
let a = [1, 2, 3, 4, 5];
// 定義一年 12 個月,而且不需要增減月份,那么可以直接定義包含 12 個月份的數組
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
// 定義包含 5 個元素的 i32 類型的數組
let a: [i32; 5] = [1, 2, 3, 4, 5];
// 數組的值是 5 個 3
let a = [3; 5];
// 取值
println!("a[3]的值是:{}", a[3]);
println!("a[9]的值是:{}", a[9]); // 編譯時這里會報錯:error: index out of bounds: the len is 5 but the index is 9
}
數組的取值方式是以中括號 [0]
的方式,順序是從 0 開始。如果取值越界,rust 會在編譯期告訴你,這就是 rust 安全原則的第一個例子。
這一節未完,待續~~~
歡迎閱讀單鵬飛的學習筆記