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);
    }