Rust語言開發
- 2022 年 2 月 18 日
- 筆記
- Rust語言程序設計
Rust開發
第一個程序
fn main() {
println!("Hello, world!"); // 帶!號的都是宏 並不是函數
}
fn main() {
let name = "peter";
println!("{}{}","Hello, world!", name);
}
cargo new projectname // 創建一個rust項目
cargo build // 構建程序為可執行程序
cargo run // 運行構建好的可執行程序
- 創建自定義函數
#![allow(non_snake_case)]
fn main() {
let name = "peter";
println!("{}{}","Hello, world!", name);
show_me()
}
fn show_me() {
let name = "peter";
let age = 21;
println!("my name is {}, age is {}", name, age)
}
- 創建模塊 使用模塊
#![allow(non_snake_case)]
fn main() {
let name = "peter";
println!("{}{}","Hello, world!", name);
lib::show_me() // 引用模塊內的函數 ::
}
mod lib {
// pub聲明函數是公有地 可以使用 模塊進行調用函數執行
pub fn show_me() {
let name = "peter";
let age = 21;
println!("my name is {}, age is {}", name, age)
}
}
- 函數傳參 定義str類型 int i32 i64 類型
#![allow(non_snake_case)]
fn main() {
let name = "peter";
println!("{}{}","Hello, world!", name);
// lib::show_me();
let uid = 101;
println!("{}", get_user(uid))
}
// &'static str 聲明str類型
// i64 i32 聲明int類型
fn get_user(uid:i64) -> &'static str {
return if uid == 101 {
"root"
} else if uid == 102 {
"$pub"
} else {
"error"
}
}
上邊的寫法 可以換成下方這種
#![allow(non_snake_case)]
fn main() {
let name = "peter";
println!("{}{}","Hello, world!", name);
// lib::show_me();
let uid = 101;
println!("{}", get_user(uid));
}
fn get_user(uid:i64) -> &'static str {
let ret = if uid == 101 {
"root"
} else if uid == 102 {
"$pub"
} else {
"error"
};
ret
}
- if 的高階寫法
let age = 2;
let new_age = if age == 2 {
5
}else {
10
};
println!("{}", age)
- for 循環
// .chars 將字符串類型轉換為可迭代對象iter
for i in text.chars(){
println!("{}",i);
};
- switch 寫法 =>match
// rust中的switch寫法match
match text.len() {
// 如果長度等於4 打印ok
4 => println!("ok!"),
// 1..=3是[1,2,3] 全部閉合
//1..3 是[1,2] 左開右閉合
// 如果text長度在5-20之間打印normal
5..=20 => println!("normal"),
// _ 否則
_ => println!("sorry"),
};
- string 堆棧
// 考慮下面這段代碼 在內存的角度發生了什麼?
let name = String::from("abc");
abc的ptr 0 a
abc的len 1 b
abc的cap 2 c
堆 棧
堆放具體的數據 棧存在數據的地址及數據的基本信息(長度, 容量, 內存地址)
語言的垃圾回收 回收的是堆
棧存放的主要是函數之類的 調用完自動回收 無需使用語言的垃圾回收器回收
RUST 常見的符號
:? -> debug
:o -> 8進制數
:x -> lower 小寫16進制數
:X -> upper 大寫16進制數
:p -> Pointer 指針
:b -> Binary 二進制
例子 :
let test = String::from("abc");
// 打印內存地址
println!("{:p}", test.as_ptr())
- 所有者 (rust語言很重要的特性ownership)
// 注: 所有者有且只能有一個
// 這個me就是String的所有者ownership
let me = String::from("abc");
// 例如 將me賦值給you me變量將失去所有String的權利屬性 you將獲得所有權變為所有者
let me = String::from("123");
let you = me;
// 解決這種問題
// 1.可以使用me.clone() 將堆棧複製開闢新的內存空間
let you = me.clone();
// 2.可以使用&me引用的方式, 這種方式you 就是me的所有者 me就是String的所有者
let you = &me;
// 如果使用下面的是沒有問題的&str不是string 執行String才會有所有權的問題
let me = "123";
let you = me;
- 所有者理解
#![allow(non_snake_case)]
fn show_len(s: &String) { // &傳入指針 就不會出現所有者 轉移的情況
println!("{}", s.len())
}
pub fn test() {
let test = String::from("abc");
show_len(&test); // 這裡如果傳入的不是指針 就相當於let s = test; 所有者轉移 後邊的內存地址是打印不出來的
// 打印內存地址
println!("{:p}", test.as_ptr())
}
// 所以在進行函數傳參時 除非這個參數後邊不在用了只給函數用了 否則我們要傳指針&類型
- 可變參數 mut
// 上述的參數都不是可變參數定義之後不可修改 聲明可變參數關鍵詞為mut
#![allow(non_snake_case)]
fn show_len(s: &mut String) { // &傳入指針 就不會出現所有者 轉移的情況
println!("{}", s.len());
s.push_str("123")
}
pub fn test() {
let mut test = String::from("abc");
show_len(&mut test); // 這裡如果傳入的不是指針 就相當於let s = test; 所有者轉移 後邊的內存地址是打印不出來的
// 打印內存地址
println!("{:p} {}", test.as_ptr(), test)
}
- 結構體 struct
struct User{
name: String,
age: i64
}
let user = User{name:String::from("zhangJiAn"), age: 123};
- Sturct 定義方法進行面向對象
// 相當於go中的 func (this *User) getUser() {}
#[derive(Debug)]
struct User{
name: String,
age: u8
}
// 實現方法的關鍵詞impl
impl User{
fn version(&self){
println!("測試rust中的方法面向對象");
}
fn to_String(&self) -> String{
format!("{}{}", self.name, self.age)
}
}
let user = User{name:String::from("zhangJiAn"), age: 123};
println!("{:?}", user);
// User { name: "zhangJiAn", age: 123 }
user.version();
// 測試rust中的方法面向對象
println!("{}", user.to_String())
// zhangJiAn123
- 數組
// 同let me: &str = "fgag"
// let tags = ["python", "vue", "js", "golang", "rust"];
let tags: [&str; 5] = ["python", "vue", "js", "golang", "rust"];
for i in tags {
println!("{}", i)
}
- 創建空數組 , 並賦值
let mut tags: [u8; 10] = [0;10];
for item in 0..tags.len() {
tags[item] = item as u8;
}
println!("{:?}", tags)
- 元祖
let tags: (&str, i32) = ("", 10);
println!("{:?}",tags)
// ("", 10)
- rust 泛型
// 泛型就是 一個函數中傳形參的時候 我可以 傳入不同類型的參數 給形參
// 這個形參的類型 由我引用的的時候自己指定即可
// model/user_model.rs
#[derive(Debug)]
pub struct UserScore <A,B>{
pub user_id: A,
pub score: B,
pub comment: &'static str,
}
pub fn get_user_score_first() -> UserScore<i32, i32> {
UserScore {
user_id: 1,
score: 90,
comment: "A類用戶",
}
}
// 泛型的關鍵 就在這 可以允許傳入不同的類型的A,B 例如 [int, str, bool] and [str, float, bool] 可以提取出bool
// UserScore中有了泛型 impl中也需要標明泛型A,B
impl <A,B> UserScore<A,B> {
pub(crate) fn get_uid(&self) -> &'static str {
&self.comment
}
}
pub fn get_user_score_second() -> UserScore<&'static str, f32> {
UserScore {
user_id: "xxx111100",
score: 90.0,
comment: "B類用戶",
}
}
// model/mod.rs
pub mod user_model;
// main.rs
let mut score = model::user_model::get_user_score_first();
score.score = 10;
println!("{:?}", score.get_uid());
let score = model::user_model::get_user_score_second();
println!("{:?}", score.get_uid());
// "A類用戶"
// "B類用戶"
- trait 共享行為 (接口設計)
trait 類似於java中的抽象類 將公共的方法抽離出來 可以被子類繼承
// api/prods.rs
use crate::model::book_model::Book;
// 定義好公共函數
pub trait Prods {
fn get_price(&self) -> f32 ;
}
// 在需要使用公共函數的方法中 實現這個 函數方法 即可
impl Prods for Book {
fn get_price(&self) -> f32 {
&self.price + 10.0
}
}
// model/book_model.rs
#[derive(Debug)]
pub struct Book {
pub id: i32,
pub price: f32
}
pub fn new_book(id: i32, price: f32) -> Book {
Book{
id,
price,
}
}
main.rs
let book = model::book_model::new_book(1, 99.9);
println!("{:?}", book.get_price())
// 109.9
- trait 簡便實例化函數
// model/book_model.rs
#[derive(Debug)]
pub struct Book {
pub id: i32,
pub price: f32
}
// api/prods.rs
use crate::model::book_model::Book;
// 定義好公共函數
pub trait Prods {
fn new(id: i32, price: f32) -> Self;
fn get_price(&self) -> f32 ;
}
// 在需要使用公共函數的方法中 實現這個 函數方法 即可 (基於Book結構體實現的Prods trait實現的方法)
impl Prods for Book {
// 基於trait實現的方法可以直接 通過方法實例化
fn new(id: i32, price: f32) -> Book {
Book{
id,
price
}
}
fn get_price(&self) -> f32 {
&self.price + 10.0
}
}
// main.rs
// 這樣使用需要 聲明book 所對應實現的struct結構體
let book: Book = api::prods::Prods::new(2, 88.8);
println!("{:?}", book.get_price())
// 98.8
- 在函數中傳遞兩個trait
// api/prods.rs
use crate::model::book_model::Book;
use crate::model::iphone_model::Phone;
// 定義好公共函數
pub trait Prods {
fn new(id: i32, price: f32) -> Self;
fn get_price(&self) -> f32 ;
}
// 在需要使用公共函數的方法中 實現這個 函數方法 即可 (基於Book結構體實現的Prods trait實現的方法)
impl Prods for Book {
// 基於trait實現的方法可以直接 通過方法實例化
fn new(id: i32, price: f32) -> Book {
Book{
id,
price
}
}
fn get_price(&self) -> f32 {
&self.price + 10.0
}
}
impl Prods for Phone {
fn new(id: i32, price: f32) -> Self {
Self {
id,
price
}
}
fn get_price(&self) -> f32 {
&self.price + 22.0
}
}
// main.rs
let book: Book = api::prods::Prods::new(2, 88.8);
let iphone: Phone = api::prods::Prods::new(3, 1500.5);
sum(book, iphone);
// 商品總價為1621.3
// 傳入兩個trait的泛型聲明
fn sum<T: Prods, U: Prods>(p1: T, p2: U) {
println!("商品總價為{}", p1.get_price()+ p2.get_price())
}
- 一個struct 對應着多個trait共享
// api/stock.rs
use crate::model::book_model::Book;
pub trait Stock{
fn get_stock(&self) -> i32;
}
impl Stock for Book {
fn get_stock(&self) -> i32 {
1000
}
}
//main.rs
use crate::api::prods::Prods;
use crate::model::book_model::Book;
use crate::model::iphone_model::Phone;
use crate::api::stock::Stock;
// 商品庫存
let book_stock: Book = api::prods::Prods::new(32, 88.0);
show_detail(book_stock)
// 商品庫存為1000
// 傳入兩個 trait使用+號聲明
fn show_detail<T>(p: T)
where T: Stock + Prods{
println!("商品庫存為{}", p.get_stock())
}
- Trait 操作符重載 (例如 +號 : 1+1 返回的是2 i32類型 重載 例如我不想他返回結果2 而是返回結果的長度 len 就是使用到操作符重載 diy )
// api/prods.rs
// +號定義的位置
// std::ops::Add 基於+號的trait共享行為 實現struct
impl std::ops::Add<Book> for Book {
type Output = f32;
fn add(self, rhs: Book) -> Self::Output {
self.get_price() + rhs.get_price()
}
}
//main.rs
let book: Book = api::prods::Prods::new(2, 88.8);
// 商品庫存
let book_stock: Book = api::prods::Prods::new(32, 88.0);
sum(book, book_stock);
fn sum(p1: Book, p2: Book) {
// println!("商品總價為{}", p1.get_price()+ p2.get_price())
println!("商品總價為{}", p1 + p2);
}
-
生命周期
- 1.作用域的生命周期
fn max (a: i32, b: i32) -> i32 { if a> b { a }else { b } } let a = 10; let b = 100; println!("{}", max(a, b)) // 如果程序這樣運行 就不會出現生命周期的問題 因為a,b 兩個參數傳參的時候相當於copy 開闢了新的內存空間存放數據 如果使用&引用 也就是指針就會出現變量的生命周期問題 // 引用生命周期 解決方法 // 這個 &' 就是生命周期的寫法 標記生命周期 fn max<'a> (a: &'a i32, b: &'a i32) -> &'a i32{ if a> b { a }else { b } } let a = 10; let b = 100; println!("{:?}", max(&a, &b))
& 引用的概念是借用的意思 被借走的數據如果沒有被歸還 是無法被修改使用的
- 生命周期 – struct中使用引用
#[derive(Debug)]
struct User<'a> {
id : &'a i32
}
fn main() {
let mut id = 109; // 好比是聲明一個汽車
let u = User{id: &id}; // 引用& 就是車被struct借走了
id=108; // 這個時候我想開車 肯定開不了 這裡就報錯了
println!("{:?}", u); // 在這執行完車才歸還給我 我在下面執行才能開車
}
- 生命周期 – &str
// 之前寫的&'static str 這個是貫穿全局的生命周期聲明
// 在輸入值和輸出值 生命周期相同 或者輸入>輸出生命周期時, 程序才允許編譯
fn show_name<'a> (name: &'a str) -> &'a str {
name
}
fn main() {
let name = "zhangsan";
show_name(name);
}
- vector 集合
數組:
1.存在棧上
2.數組是rust內置的數據類型
3.長度固定
vector 與數組正好相反
1.存在堆上
2.長度可以自動擴容
3.第三方庫
// let vec_tags = vec!["go", "py", "rust"];
// 兩種聲明是相同的 寫法不同
let mut vec_tags = Vec::new();
// 注: &str 是不可變類型
vec_tags.push(String::from("go"));
vec_tags.push(String::from("vue"));
vec_tags.push(String::from("js"));
for i in &mut vec_tags {
// i = i+"1";
// 如果要對vec集合中的元素 進行修改 需要保證遍歷的元素是可修改的 *是反解&的 &就是引用內存地址 加上*之後 是顯示真實數據
*i += "hae";
println!("{:?}", i)
}
println!("{:?}", vec_tags);
// ["gohae", "vuehae", "jshae"]
- 枚舉
枚舉理解下來 應該是用來約束數據類型的
#[derive(Debug)]
enum Sex {
Male(String), // ()內可以定義多個類型 例如(String, i32)
FeMale(String)
}
#[derive(Debug)]
struct User {
id: i32,
sex: Sex
}
fn check_sex(u: User) {
// 判斷 u.sex 數據類型 和 Sex是否匹配
if let Sex::Male(s) = u.sex {
println!("{:?}", s)
}
}
// enumerate 枚舉例子
fn enumerate() {
println!("{:?}", Sex::Male(String::from("man")
));
// Male("man")
println!("{:?}", User{id:1, sex:Sex::Male(String::from("man"))});
// User { id: 1, sex: Male("man") }
let u = User{id:1, sex:Sex::Male(String::from("man"))};
check_sex(u);
}
-
內置枚舉 取代 自定義枚舉
#[derive(Debug)] struct User { id: i32, // sex: Sex sex: Option<String> } fn check_sex(u: User) { // 判斷 u.sex 數據類型 和 Sex是否匹配 // if let Sex::Male(s) = u.sex { if let Some(s) = u.sex { println!("{:?}", s) // "man" } } // enumerate 枚舉例子 fn enumerate() { let u = User{id:1, sex: Some(String::from("man")) }; check_sex(u); }