【Rust】001-基礎(chǔ)語(yǔ)法:變量聲明及數(shù)據(jù)類型
一、概述
1、學(xué)習(xí)起源
“一切能用 Rust 重寫(xiě)的項(xiàng)目都將或者正在用 Rust 重寫(xiě)”
2、依托課程
Rust 入門(mén)與實(shí)踐:https://juejin.cn/book/7269676791348854839?utm_source=course_list
二、入門(mén)程序
1、Hello World
fn main() {
// 打印字符串
println!("Hello, world!");
}
2、交互程序
代碼演示
use std::io; // 使用標(biāo)準(zhǔn)庫(kù)中的 io 這個(gè)模塊
fn main() {
// 打印字符串
println!("Hello, world!");
// 打印字符串
println!("請(qǐng)輸入一個(gè)數(shù)字: ");
// 在這里我們創(chuàng)建了一個(gè)新的 String,用來(lái)接收下面的輸入
let mut input = String::new();
io::stdin()
.read_line(&mut input) // 讀取一行
.expect("Failed to read input!"); // 比較粗暴的錯(cuò)誤處理
// 打印輸入的原始內(nèi)容
println!("Your raw input is: {:?}.", input);
// trim 把前后的空格、換行符這些空白字符都去掉,parse 將輸入的字符串解析為 i64 類型,如果解析失敗就報(bào)錯(cuò)
let number: i64 = input.trim().parse().expect("Input is not a number!");
// 打印 parse 之后的 i64 數(shù)字
println!("Your input is: {}.", number);
}
執(zhí)行結(jié)果
C:/Users/Administrator/.cargo/bin/cargo.exe run --color=always --package hello_rust --bin hello_rust
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target\debug\hello_rust.exe`
Hello, world!
請(qǐng)輸入一個(gè)數(shù)字:
100
Your raw input is: "100\n".
Your input is: 100.
進(jìn)程已結(jié)束,退出代碼為 0
3、繼續(xù)上難度:訪問(wèn)鏈接并打印響應(yīng)
依賴
Cargo.toxml
[package]
name = "hello_rust"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4", features = ["derive"] }
reqwest = { version = "0.11", features = ["blocking"] }
代碼
// 使用 use 引入一個(gè)標(biāo)準(zhǔn)庫(kù)的包,或者第三方的包
use std::error::Error;
// clap 是一個(gè) Rust 社區(qū)開(kāi)發(fā)的命令行參數(shù)解析庫(kù)
use clap::Parser;
// reqwest 是一個(gè) Rust 社區(qū)開(kāi)發(fā)的 HTTP 客戶端庫(kù)
use reqwest::blocking::Client;
use reqwest::header::HeaderMap;
// 使用 derive 宏,用于自動(dòng)生成 Parser 的實(shí)現(xiàn)
// 在高級(jí)特性章節(jié)中我們會(huì)學(xué)到宏的用法及原理
#[derive(Parser)]
#[command(
author,
version,
about = "Sends HTTP requests and prints detailed information"
)]
struct Cli {
// arg 宏用于標(biāo)記命令行參數(shù),這里標(biāo)記了一個(gè)必須的 URL 參數(shù)
#[arg(short, long, help = "Target URL", required = true)]
url: String,
}
/// Rust 程序入口
fn main() -> Result<(), Box<dyn Error>> {
// 解析命令行參數(shù)
let cli = Cli::parse();
// 發(fā)起 HTTP 請(qǐng)求
// ? 是 Rust 中的錯(cuò)誤傳播語(yǔ)法糖,我們會(huì)在接下來(lái)的章節(jié)中學(xué)習(xí)
let response = send_request(&cli.url)?;
// 打印 HTTP 響應(yīng)的詳細(xì)信息
print_response_details(response)?;
Ok(())
}
/// 發(fā)起一個(gè) HTTP 請(qǐng)求
/// 參數(shù)是目標(biāo) URL 的引用
/// 返回值是一個(gè) Result,如果請(qǐng)求成功返回 Response,否則返回一個(gè)動(dòng)態(tài) Error
fn send_request(url: &str) -> Result<reqwest::blocking::Response, Box<dyn Error>> {
// 創(chuàng)建一個(gè) HTTP 客戶端
let client = Client::builder().build()?;
// 使用 GET 方法發(fā)起請(qǐng)求
let response = client.get(url).send()?;
Ok(response)
}
/// 打印出 HTTP 響應(yīng)的詳細(xì)信息
/// 參數(shù)是 Response 對(duì)象
/// 返回值是一個(gè) Result,用于錯(cuò)誤處理
fn print_response_details(response: reqwest::blocking::Response) -> Result<(), Box<dyn Error>> {
// 打印 HTTP 狀態(tài)碼
println!("Status: {}", response.status());
// 打印 HTTP 響應(yīng)頭
println!("Headers:");
print_headers(response.headers());
// 讀取并打印 HTTP 響應(yīng)體
let body = response.text()?;
println!("Body:\n{}", body);
Ok(())
}
/// 打印出 HTTP 響應(yīng)頭
/// 參數(shù)是 HeaderMap 的引用
fn print_headers(headers: &HeaderMap) {
for (key, value) in headers.iter() {
// 打印每個(gè)響應(yīng)頭的鍵和值
// 如果值不是 UTF-8 字符串,就打印 [unprintable]
println!(" {}: {}", key, value.to_str().unwrap_or("[unprintable]"));
}
}
執(zhí)行命令
根目錄執(zhí)行
cargo run -- --url https://juejin.cn/
三、數(shù)據(jù)類型
1、標(biāo)量類型
整型標(biāo)量類型

只要記得最低從 8 開(kāi)始,到 128 結(jié)束(當(dāng)然,正常情況下我們最多用到 64,128 在很多平臺(tái)上需要軟件模擬而不是硬件支持,不推薦大家用);在賦值的時(shí)候除了直接十進(jìn)制數(shù)字賦值外,還支持以下語(yǔ)法(大家了解一下就好,不用死記硬背):
其它
- 浮點(diǎn)數(shù):f32 / f64
- bool
- char:這個(gè)比較特殊,Rust 中一個(gè) char 占 4 字節(jié),存放的是一個(gè) UTF-32,而不像 C/C++ 那樣本質(zhì)上是個(gè) u8
2、復(fù)合類型
- 元組 tuple:let a = (1, 2); let (a, b) = (1, 2)
- 數(shù)組 array: let a = [1, 2, 3]; let a = [0; 5] // 這個(gè)聲明中 0 是默認(rèn)值,5 是長(zhǎng)度,等價(jià)于 let a = [0, 0, 0, 0, 0]
四、變量聲明與使用
1、常量
代碼演示
fn main() {
// 聲明常量,表示年齡
const AGE: u32 = 18;
// 聲明常量,表示名字
let name = "張三";
// 打印名字和年齡
println!("{}的年齡是{}", name, AGE);
}
執(zhí)行結(jié)果
張三的年齡是18
2、變量
代碼演示
fn main() {
// 聲明變量,表示年齡
let mut age = 18;
// 打印變量
println!("age = {}", age);
// 修改變量
age = 20;
// 打印變量
println!("age = {}", age);
}
執(zhí)行結(jié)果
age = 18
age = 20
3、變量名復(fù)用
代碼演示
fn main() {
// 聲明常量,表示年齡
let age = 18;
// 打印年齡
println!("age = {}", age);
// 再次聲明 age 變量,此時(shí)不會(huì)報(bào)錯(cuò)
let age = 20;
// 打印年齡
println!("age = {}", age);
}
執(zhí)行結(jié)果
age = 18
age = 20
4、聲明時(shí)指定變量類型
代碼演示
fn main() {
// 聲明常量,表示年齡
let age: i32 = 18;
// 打印年齡
println!("age = {}", age);
}
執(zhí)行結(jié)果
age = 18
age = 20
5、元組的使用
代碼演示
fn main() {
// 聲明一個(gè)包含三個(gè)元素的元組
let my_tuple = (1, "hello", 3.14);
// 使用索引訪問(wèn)元組中的元素
println!("第一個(gè)元素是:{}", my_tuple.0); // 輸出 "第一個(gè)元素是:1"
println!("第二個(gè)元素是:{}", my_tuple.1); // 輸出 "第二個(gè)元素是:hello"
println!("第三個(gè)元素是:{}", my_tuple.2); // 輸出 "第三個(gè)元素是:3.14"
// 使用模式匹配解構(gòu)元組
let (x, y, z) = my_tuple;
println!("解構(gòu)后 x 的值是:{}", x); // 輸出 "解構(gòu)后 x 的值是:1"
println!("解構(gòu)后 y 的值是:{}", y); // 輸出 "解構(gòu)后 y 的值是:hello"
println!("解構(gòu)后 z 的值是:{}", z); // 輸出 "解構(gòu)后 z 的值是:3.14"
// 忽略元組中不需要的值
let (a, _, _) = my_tuple;
println!("只需要第一個(gè)元素:{}", a); // 輸出 "只需要第一個(gè)元素:1"
// 嵌套元組
let nested_tuple = (1, (2, 3), 4);
let (_, (b, c), _) = nested_tuple;
println!("嵌套元組中 b 的值和 c 的值分別是:{} 和 {}", b, c); // 輸出 "嵌套元組中 b 的值和 c 的值分別是:2 和 3"
}
執(zhí)行結(jié)果
第一個(gè)元素是:1
第二個(gè)元素是:hello
第三個(gè)元素是:3.14
解構(gòu)后 x 的值是:1
解構(gòu)后 y 的值是:hello
解構(gòu)后 z 的值是:3.14
只需要第一個(gè)元素:1
嵌套元組中 b 的值和 c 的值分別是:2 和 3
6、數(shù)組的使用
代碼演示
fn main() {
// 聲明一個(gè)包含5個(gè)元素的整數(shù)數(shù)組
let int_array = [1, 2, 3, 4, 5];
// 聲明一個(gè)包含5個(gè)元素的浮點(diǎn)數(shù)數(shù)組,同時(shí)指定類型
let float_array: [f64; 5] = [1.0, 2.0, 3.0, 4.0, 5.0];
// 使用索引訪問(wèn)數(shù)組中的元素
println!("整數(shù)數(shù)組的第一個(gè)元素是:{}", int_array[0]); // 輸出 "整數(shù)數(shù)組的第一個(gè)元素是:1"
println!("浮點(diǎn)數(shù)數(shù)組的第二個(gè)元素是:{}", float_array[1]); // 輸出 "浮點(diǎn)數(shù)數(shù)組的第二個(gè)元素是:2.0"
// 使用循環(huán)遍歷整數(shù)數(shù)組
println!("整數(shù)數(shù)組的所有元素:");
for num in int_array.iter() {
print!("{} ", num); // 輸出 "1 2 3 4 5 "
}
println!();
// 使用循環(huán)遍歷浮點(diǎn)數(shù)數(shù)組,并獲取索引
println!("浮點(diǎn)數(shù)數(shù)組的所有元素和對(duì)應(yīng)的索引:");
for (index, num) in float_array.iter().enumerate() {
println!("索引:{}, 元素:{}", index, num);
// 輸出 "索引:0, 元素:1.0"
// 輸出 "索引:1, 元素:2.0"
// ...
}
// 聲明一個(gè)全部元素為0的數(shù)組
let zero_array: [i32; 5] = [0; 5];
println!("全為0的數(shù)組:{:?}", zero_array); // 輸出 "全為0的數(shù)組:[0, 0, 0, 0, 0]"
}
執(zhí)行結(jié)果
整數(shù)數(shù)組的第一個(gè)元素是:1
浮點(diǎn)數(shù)數(shù)組的第二個(gè)元素是:2
整數(shù)數(shù)組的所有元素:
1 2 3 4 5
浮點(diǎn)數(shù)數(shù)組的所有元素和對(duì)應(yīng)的索引:
索引:0, 元素:1
索引:1, 元素:2
索引:2, 元素:3
索引:3, 元素:4
索引:4, 元素:5
全為0的數(shù)組:[0, 0, 0, 0, 0]
7、字符串
代碼演示
fn main() {
// 使用字符串字面量聲明一個(gè)不可變字符串
let hello_str = "Hello, world!";
println!("不可變字符串字面量:{}", hello_str); // 輸出 "不可變字符串字面量:Hello, world!"
// 使用 String::from 創(chuàng)建一個(gè)可變字符串
let mut hello_string = String::from("Hello");
println!("可變字符串:{}", hello_string); // 輸出 "可變字符串:Hello"
// 在可變字符串后追加字符串
hello_string.push_str(", world!");
println!("追加后的可變字符串:{}", hello_string); // 輸出 "追加后的可變字符串:Hello, world!"
// 字符串拼接
let concat_str = [hello_str, " ", &hello_string].concat();
println!("拼接后的字符串:{}", concat_str); // 輸出 "拼接后的字符串:Hello, world! Hello, world!"
// 使用索引獲取字符串中的字符(注意:這種方式不推薦,因?yàn)闀?huì)導(dǎo)致錯(cuò)誤或崩潰)
// let first_char = hello_str[0]; // 這樣是錯(cuò)誤的
// Rust 的字符串是 UTF-8 編碼的,直接索引可能會(huì)導(dǎo)致字符被截?cái)唷?/span>
// 使用 chars 方法遍歷字符串中的字符
println!("使用 chars 方法遍歷字符串:");
for ch in hello_str.chars() {
print!("{} ", ch); // 輸出 "H e l l o , w o r l d ! "
}
println!();
// 使用 bytes 方法遍歷字符串中的字節(jié)
println!("使用 bytes 方法遍歷字符串字節(jié):");
for byte in hello_str.bytes() {
print!("{} ", byte); // 輸出對(duì)應(yīng)的 ASCII 或 UTF-8 編碼的字節(jié)值
}
println!();
// 獲取字符串長(zhǎng)度
println!("字符串 '{}' 的長(zhǎng)度是:{}", hello_str, hello_str.len()); // 輸出 "字符串 'Hello, world!' 的長(zhǎng)度是:13"
}
執(zhí)行結(jié)果
不可變字符串字面量:Hello, world!
可變字符串:Hello
追加后的可變字符串:Hello, world!
拼接后的字符串:Hello, world! Hello, world!
使用 chars 方法遍歷字符串:
H e l l o , w o r l d !
使用 bytes 方法遍歷字符串字節(jié):
72 101 108 108 111 44 32 119 111 114 108 100 33
字符串 'Hello, world!' 的長(zhǎng)度是:13
五、演示 Ownership(所有權(quán))、Borrowing(借用) 和 Lifetime(生命周期) 的基本概念的示例
代碼演示
// 定義一個(gè)函數(shù),演示所有權(quán)的轉(zhuǎn)移
fn takes_ownership(some_string: String) {
println!("函數(shù)內(nèi)部:{}", some_string);
} // 這里 some_string 離開(kāi)作用域,所有權(quán)也隨之釋放
// 定義一個(gè)函數(shù),演示借用(不可變)
fn borrows_immutable(s: &String) {
println!("函數(shù)內(nèi)部(不可變借用):{}", s);
}
// 定義一個(gè)函數(shù),演示借用(可變)
fn borrows_mutable(s: &mut String) {
s.push_str(", world!"); // 修改字符串
println!("函數(shù)內(nèi)部(可變借用):{}", s);
}
// 定義一個(gè)函數(shù),演示生命周期
// 注:'a 是生命周期標(biāo)注,表明 x 和 y 的生命周期相同,并且與返回值的生命周期也相同
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
// 所有權(quán)(Ownership)
let s1 = String::from("hello"); // s1 獲取了字符串 "hello" 的所有權(quán)
takes_ownership(s1); // 所有權(quán)轉(zhuǎn)移到函數(shù) takes_ownership
// println!("main 函數(shù):{}", s1); // 錯(cuò)誤!因?yàn)?s1 的所有權(quán)已經(jīng)被轉(zhuǎn)移
// 借用(Borrowing)
let s2 = String::from("hello"); // s2 獲取了字符串 "hello" 的所有權(quán)
borrows_immutable(&s2); // 不可變借用,所有權(quán)仍在 s2
println!("main 函數(shù)(不可變借用后):{}", s2);
let mut s3 = String::from("hello"); // s3 獲取了字符串 "hello" 的所有權(quán),并且是可變的
borrows_mutable(&mut s3); // 可變借用,所有權(quán)仍在 s3,但內(nèi)容已經(jīng)被修改
println!("main 函數(shù)(可變借用后):{}", s3);
// 生命周期(Lifetime)
let str1 = "Rust";
let str2 = "Programming";
let result = longest(str1, str2);
println!("更長(zhǎng)的字符串是:{}", result); // 輸出 "更長(zhǎng)的字符串是:Programming"
}
執(zhí)行結(jié)果
函數(shù)內(nèi)部:hello
函數(shù)內(nèi)部(不可變借用):hello
main 函數(shù)(不可變借用后):hello
函數(shù)內(nèi)部(可變借用):hello, world!
main 函數(shù)(可變借用后):hello, world!
更長(zhǎng)的字符串是:Programming
六、const 和 let 的區(qū)別
1. 可變性(Mutability)
-
let
: 默認(rèn)情況下,使用let
聲明的變量是不可變的,但您可以使用mut
關(guān)鍵字來(lái)使其可變。let x = 5; // 不可變 let mut y = 6; // 可變
-
const
: 使用const
聲明的常量始終是不可變的,并且不能使用mut
。const X: i32 = 5; // 始終不可變
2. 類型注解
-
let
: 可以選擇是否添加類型注解。let x = 5; // 類型推斷為 i32 let y: i64 = 6; // 顯示類型注解
-
const
: 必須添加類型注解。const X: i32 = 5; // 必須提供類型
3. 初始化表達(dá)式
-
let
: 可以使用任何類型的表達(dá)式進(jìn)行初始化。let x = 5 + 5; // 算術(shù)表達(dá)式
-
const
: 只能使用常量表達(dá)式進(jìn)行初始化。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-692407.htmlconst X: i32 = 5 + 5; // 常量表達(dá)式,但不能是函數(shù)調(diào)用、運(yùn)行時(shí)計(jì)算等
4. 作用域和生命周期
-
let
: 局部變量,作用范圍僅限于聲明它的代碼塊。 -
const
: 可以在模塊級(jí)別使用,生命周期可跨越整個(gè)程序。
5. 內(nèi)聯(lián)
-
const
: 在編譯時(shí),常量的值會(huì)被直接內(nèi)聯(lián)到使用它的表達(dá)式中。 -
let
: 取決于編譯器優(yōu)化。
總體來(lái)說(shuō),const
主要用于那些在編譯時(shí)就能確定并且永遠(yuǎn)不會(huì)改變的值,而 let
則用于運(yùn)行時(shí)可能會(huì)改變的值。希望這能幫助您更好地理解這兩者之間的區(qū)別!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-692407.html
到了這里,關(guān)于【Rust】001-基礎(chǔ)語(yǔ)法:變量聲明及數(shù)據(jù)類型的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!