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結構體例項的屬性賦值也有兩種方式:
- 屬性逐一賦值
- 雙點號複製屬性值
例如以下就是:
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()), }; }
結構體的函式有幾個特點:
- 在結構體外,使用impl xxxx {}的方式,其中xxx是結構體名稱
- 在一個impl xxx{}結構中,可以定義多個函式
- 書本建議我們:函式的第一個方法總是 &self,這點和python有點類似
- 引數&self雖然有定義,但是呼叫的時候不需要顯示傳遞,因為這是編譯器實現的
四、小結
結構體無疑是一個有用的東西,它就算垃圾袋/寶物袋一樣,什麼都可以往裡裝,大大方便了工程師!