首頁 > 軟體

解析rust中的struct

2022-10-10 14:01:17

定義struct

  • 使用struct關鍵字,併為整個struct命名
  • 在花括號內,為所有欄位(field)定義名稱和型別
struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

範例化struct

  • 想要使用struct,需要建立strut的範例
  • 為每個欄位知道具體值
  • 無需按宣告的順序進行指定
struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main(){
    let user1 = User{
        username: String::from("xxxx"),
        email: String::from("xxxx@163.com"),
        active: true,
        sign_in_count:556,
    };
    println!("username:{}", user1.username);
    println!("email:{}", user1.email);
    println!("active:{}", user1.active);
    println!("sign_in_count:{}", user1.sign_in_count);
}

取得struct裡面的某個值

使用點標記法

struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main(){
    let mut user1 = User{
        username: String::from("xxxx"),
        email: String::from("xxxx@163.com"),
        active: true,
        sign_in_count:556,
    };
    // 注意 user1 必須是可變的 
    user1.username = String::from("hhhhhhh");
    println!("username:{}", user1.username);
    println!("email:{}", user1.email);
    println!("active:{}", user1.active);
    println!("sign_in_count:{}", user1.sign_in_count);
}

注意

一旦struct的範例是可變的,那麼範例中的所有欄位都是可以變的

struct作為函數的放回值

struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn build_user(email: String, username: String)-> User{
    User{
        email: email,
        username: username,
        active: true,
        sign_in_count:1,
    }
}

fn main(){
    let email = String::from("xxxx@163.com");
    let username = String::from("llllll");
    let user1 = build_user(email, username);
    println!("username:{}", user1.username);
    println!("email:{}", user1.email);
    println!("active:{}", user1.active);
    println!("sign_in_count:{}", user1.sign_in_count);
}

欄位初始化簡寫

當欄位名與欄位值對應變數名相同時,就可以使用欄位初始化簡寫的方式

fn build_user(email: String, username: String)-> User{
    User{
        email,
        username,
        active: true,
        sign_in_count:1,
    }
}

struct更新語法

當你想基於某個struct範例來建立一個新範例的時候,可以使用struct更新語法

struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn build_user(email: String, username: String)-> User{
    User{
        email,
        username,
        active: true,
        sign_in_count:1,
    }
}

fn main(){
    let email = String::from("xxxx@163.com");
    let username = String::from("llllll");
    let user1 = build_user(email, username);
    // user2 email 重新賦值
    // user2 其他變數 使用 user1 的值
    // String 型別會被參照 從而失效
    let user2 = User{
        email: String::from("user2@163.com"),
        ..user1
    };
    // user1.username 被 user2.username 參照 從而失效
    // println!("username:{}", user1.username);
    println!("username:{}", user2.username);
    println!("email:{}", user1.email);
    println!("email:{}", user2.email);
    println!("active:{}", user1.active);
    println!("sign_in_count:{}", user1.sign_in_count);
}

tuple struct

  • 可定義類似tuple的struct,叫做tuple struct
  • tuple struct 整體有個名,但裡面的元素沒有名
  • 適用:想給整個tuple起名,並且它不同於其它tuple,而且又不需要給每個元素
  • 定義tuple struct:使用struct關鍵字,後邊是名字,以及裡面元素的型別
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 2, 3);
let origin = Point(3, 2, 3);

Unit-Like Struct(沒有任何欄位)

  • 可以定義沒有任何的struct,叫做Unit-Like struct(因為與{},單元型別類似)
  • 使用與需要在某個型別上失效某個trait,但是在裡面有沒有想要儲存的資料結構

struct資料的所有權

struct User{
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}
  • 這裡的欄位使用了String而不是&str
  • 改struct範例擁有其所有的資料
  • 只有struct範例是有效的,那麼裡面的欄位也是有效的
  • struct裡面也是存放參照,但是需要使用生命週期

什麼事struct

  • std::fmt::Display
  • std::fmt::Debug
  • #[derive(Debug)]
  • {:?}
  • {:#?}
#[derive(Debug)]
struct Rectangle{
    width: u32,
    length: u32,
}
fn main(){
    let rect = Rectangle{
        width: 22,
        length: 44,
    };
    println!("{}", area(&rect));
    println!("{:?}", rect);
    println!("{:#?}", rect);
}
fn area(rect: &Rectangle)-> u32{
    rect.length * rect.width
}

struct的方法

  • 方法和函數類似:fn關鍵字、名稱、引數、返回值
  • 方法與函數不同之處
  • 方法是在struct(或enum、trait物件)的上下文中定義
  • 第一個引數是self,表示方法被呼叫的struct範例

定義方法

#[derive(Debug)]
struct Rectangle{
    width: u32,
    length: u32,
}
impl Rectangle{
    fn area(&self)-> u32{
        self.width * self.length
    }
}
fn main(){
    let rect = Rectangle{
        width: 33,
        length: 44,
    };
    println!("{}", rect.area());
    println!("{:#?}", rect);
}
  • 在impl塊裡定義方法
  • 方法的第一個引數可以是&self,也可以獲得其所有權或可變借用。其他引數一樣。
  • 更良好的程式碼組織。

​​​​​​​​​​​​​​方法呼叫的運運算元

  • C/C++:object->somthing()和(*object).something()一樣
  • rust沒有->運運算元
  • rust會自動參照或解除參照
  • 在呼叫方法時就會發生這種行為
  • 在呼叫方法時,rust根據情況自動新增&、&mut或*,以便object可以匹配方法的簽名。
  • 下面兩行程式碼效果相同
p1.distance(&p2);
(&p1).distance(&p2);

關聯函數

  • 可以在impl塊裡定義不把self作為第一個引數的函數,它們叫做關聯函數(不是方法)
String::from();
  • 關聯函數通常用於構造器
  • ::符號
  • 關聯函數
  • 模組建立的名稱空間
#[derive(Debug)]
struct Rectangle{
    width: u32,
    length: u32,
}
impl Rectangle{
    fn square(width: u32, length: u32)->Rectangle{
        Rectangle{
            width,
            length,
        }
    }
}
fn main(){
    let rect = Rectangle::square(33, 11);
    println!("width:{}", rect.width);
    println!("length:{}", rect.length);
    println!("{:#?}", rect);
}

多個impl塊

  • 每個struct執行擁有多個impl塊

到此這篇關於解析rust中的struct的文章就介紹到這了,更多相關rust struct內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com