rust学习六、简单的struct结构
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虽然有定义,但是调用的时候不需要显示传递,因为这是编译器实现的
四、小结
结构体无疑是一个有用的东西,它就算垃圾袋/宝物袋一样,什么都可以往里装,大大方便了工程师!