rust學習六、簡單的struct結構

正在战斗中發表於2024-11-06

rust的struct結構體是一個不錯的東西,不像java,後者在17版本左右才可用。

有許多語言都有類似的東西,例如pascal有record。

本文主要根據<<The rust programming language>>相關章節編寫。

一、結構定義

struct-翻譯為結構/結構體

總體上有兩種定義方式:帶有詳細屬性名的;不帶屬性名(元組)

從工程角度出發,並不推薦不帶屬性的定義方式,因為不友好。希望rust後面不要搞類似好像很友好,但是其實起到干擾作用的語法。

如果再考慮到一些rust的其它問題,定義一個結構其實也不是那麼容易。

示例:

struct Point{x:f64,y:f64}
struct Triangle(Point,Point,Point);

/**
 * 家庭結構體s
 */
struct Family {
    name: String,
    father: String,
    mather: String,
    children: Vec<String>,
}
/**
 * 這都什麼狗屎語法。
 */
struct Book<'a> {
    name: &'a str,
    author: &'a str,
    price: f64,
    pubyear: i32,
}


fn main() {
    let mut family = Family {
        name: String::from(""),
        father: String::from("爸爸"),
        mather: String::from("媽媽"),
        children: vec![],
    };

    family.children.push(String::from("老大-獨龍"));
    family.children.push(String::from("老二-獨眼"));
    family.children.push(String::from("老三-獨秀"));
    family.children.push(String::from("老四-嘟嘟"));
    family.children.push(String::from("老五-杜牧"));

    //列印家庭結構體
    println!(
        "家庭:{},父親:{},母親:{}",
        family.name, family.father, family.mather
    );
    for child in &family.children {
        println!("孩子:{}", child);
    }


    let mut 三國演義 = Book {
        name: "三國演義",
        author: "羅貫中",
        price: 29.8,
        pubyear: 1300,
    };
    
    //各種建立結構例項的方式
    // 方式一:雙點號複製
    let mut 紅樓夢=Book{
        name:"紅樓夢",
        author:"曹雪芹",
        ..三國演義
    };
    //方式二: 略屬性名
    let 西遊記=write_book("西遊記","吳承恩",24.0,1525);
    //方式三:使用基於元組定義的。 比java的record還簡單

    let books=[三國演義,紅樓夢,西遊記];
    for i in 0..books.len() {
        print_book(&books[i]);
    }
    let p1=Point{x:10.0,y:20.0};
    let p2=Point{x:20.0,y:20.0};
    let p3=Point{x:20.0,y:10.0};
    let t=Triangle(p1,p2,p3);
    print_triangle(&t);
}

fn print_book(book:&Book){
    println!(
        "書名:{},作者:{},價格:{},出版年:{}",
        book.name, book.author, book.price, book.pubyear
    );
}

fn print_triangle(t:&Triangle){
    println!("三點座標:");
    println!("{},{}",t.0.x,t.0.y);
    println!("{},{}",t.1.x,t.1.y);
    println!("{},{}",t.2.x,t.2.y);
}

fn write_book<'a>(name:&'a str,author:&'a str,price:f64,pubyear:i32)->Book<'a>{
    Book{
        name,
        author,
        price,
        pubyear
    }
}

在上例中,結構Book使用了非常奇怪的語法:

struct Book<'a> {
name: &'a str,
author: &'a str,
price: f64,
pubyear: i32,
}
這個能夠定義出來,是因為編譯器提示的。
作為初學者,先繞過這個吧。
rust結構體例項的屬性賦值也有兩種方式:
  1. 屬性逐一賦值
  2. 雙點號複製屬性值

例如以下就是:

let mut 紅樓夢=Book{
        name:"紅樓夢",
        author:"曹雪芹",
        ..三國演義
    };

二、幾種列印方式

至少有4種列印方式:

  • 逐一訪問屬性名
  • println!使用宏符號:?
  • println!使用宏符號:#?
  • 使用dbg!

後面三種方式,要求定義結構的時候,在結構前新增

#[derive(Debug)]

這個東西應該怎麼稱呼了? "屬性"還是"編譯指示符"?,有點亂七八雜的。
從宏觀上而言,很多類似的都是可以稱為編譯指示符,所以為了更加精準一些,我願意稱為"功能編譯指示"。
透過這個功能編譯指示,rust編譯器會自動實現特定功能。
示例:
#[derive(Debug)]
struct Family{
    father:String,
    mather:String,
    address:String
}

fn main(){
    let mut mf=Family{
        father:String::from("lu"),
        mather:String::from("hu"),
        address:String::from("中國")
    };
    println!("我家-{},{},{}",mf.father,mf.mather,mf.address);
    print_family(&mf);
    print_family_use_dbg(&mf);
}

fn print_family(f:&Family){
    //你不能直接列印,否則會有奇奇怪怪的錯誤提示
    //println!("{}",f);  // 這個會提示錯誤,所以註釋掉了

    //使用奇怪符號 :?列印結構體
    println!("我家:?-{:?}",f);

    //使用奇怪的符號,可以列印結構體 :#?
    println!("我家:#?-{:#?}",f);
}

fn print_family_use_dbg(f:&Family){
    dbg!(f);
}

三、定義結構內的函式

在沒有看書本正文之前,我以為和java的record一樣,在struct內部定義函式。

其實不是! 如果要為結構體定義函式,必須在結構體外。 不知道為什麼要那樣? 難道內部定義的話,有其它用途?

示例:

#[derive(Debug)]
struct Cube{
    length: u32,
    width: u32,
    height: u32,
}
impl Cube{
    fn volume(&self) -> u32{
        return self.length * self.width * self.height;
    }
    fn is_bigger_than(&self, other: &Cube) -> bool{
        return self.volume() > other.volume();
    }

}

fn main() {
    let cube = Cube{length: 10, width: 12, height: 25};
    let cube2 = Cube{length: 15, width: 10, height: 30};
    println!("立方體的體積={}立方厘米",cube.volume());
    let is_bigger = cube.is_bigger_than(&cube2);
    match is_bigger{
        true => println!("cube的體積{}大於cube2體積{}",cube.volume(), cube2.volume()),
        false =>println!("cube的體積{}小於cube2體積{}",cube.volume(), cube2.volume()),
    };
}

結構體的函式有幾個特點:

  1. 在結構體外,使用impl xxxx {}的方式,其中xxx是結構體名稱
  2. 在一個impl xxx{}結構中,可以定義多個函式
  3. 書本建議我們:函式的第一個方法總是 &self,這點和python有點類似
  4. 引數&self雖然有定義,但是呼叫的時候不需要顯示傳遞,因為這是編譯器實現的

四、小結

結構體無疑是一個有用的東西,它就算垃圾袋/寶物袋一樣,什麼都可以往裡裝,大大方便了工程師!

相關文章