结构体
🧰

结构体

创建时间
Nov 12, 2024 02:41 PM
上次编辑时间
Last updated November 14, 2024
标签
rust
基础
入门
结构体

命名结构体

  • 有些也称作为具名结构体,就是指每个字段都有名字的结构体,它的每个字段都有明确的名字和类型。
#[derive(Debug)] struct Person { name: String, age: u32, role: String, } struct _Society { year: u32, persons: Vec<Person>, // struct可作为另一个struct的变量类型 } fn main() { let farmer = Person { name: String::from("ohBug"), age: 18, role: String::from("Farmer"), }; let name = String::from("Qidai"); let age = 22; let mut busi_man = Person { name, age, role: String::from("busi_man"), }; println!("busi_man = {:?}", busi_man); println!("Farmer = {:?}", farmer); // 更新字段,注意busi_man是mut修饰 busi_man.name = String::from("beggar"); println!("busi_man = {:?}", busi_man); let busi_man_name = busi_man.name; println!("busi_man_name = {}", busi_man_name); // error 因为name字段是String类型,所以有所有权概念,现在所有权已经归属于 busi_man_name,所以不能整体打印 busi_man // println!("busi_man = {:?}", busi_man); // 但是可以打印没有被影响的字段 println!("busi_man = {:?}", busi_man.role); let farmer_two = Person { name: String::from("twoxx"), age: 45, ..farmer // farmer的role并不会变,可使用此种赋值方式。 }; println!("farmer_two = {:?}", farmer_two) } // output busi_man = Person { name: "Qidai", age: 22, role: "busi_man" } Farmer = Person { name: "ohBug", age: 18, role: "Farmer" } busi_man = Person { name: "beggar", age: 22, role: "busi_man" } busi_man_name = beggar busi_man = "busi_man" farmer_two = Person { name: "twoxx", age: 45, role: "Farmer" }

匿名结构体

  • 也叫做元组结构体,就是元组和结构体的结合体。
#[derive(Debug)] struct point_2d { x: i32, y: i32, } #[derive(Debug)] struct circle_2d { point: point_2d, radius: i32, } // 元组结构体,对于一些结构描述的更加清晰直接 #[derive(Debug)] struct circle((i32, i32), i32); fn main() { let point = point_2d { x: 31, y: 42 }; let _circle = circle_2d { point, radius: 12 }; println!("{:?}", _circle); // 元组结构体 let tuple_circle = circle((31, 42), 12); println!("{:?}", tuple_circle); } // output circle_2d { point: point_2d { x: 31, y: 42 }, radius: 12 } circle((31, 42), 12)

单元结构体

  • 像是一种标识。
#[derive(Debug)] struct FLAG; fn main() { let flag = FLAG; println!("{:?}", flag) } //ouput FLAG

面向对象

构造方法

  • 没有类似Java的构造方法,需要自己实现。
// Default 默认构造器,就是将Person初始化的时候,对象中的各个字段都是默认值 #[derive(Debug, Default)] struct Person { name: String, age: u32, } impl Person { // 构造,new只是方法名,并非强制 fn new(name: &str, age: u32) -> Person{ Person { name: name.to_string(), age, } } } fn main() { let person = Person::new("ohBug", 20); println!("{:?}", person); let default_person = Person::default(); // 与上面作用一样 // let default_person: Person = Default::default(); println!("{:?}", default_person); } //output Person { name: "ohBug", age: 20 } Person { name: "", age: 0 }

实例方法&静态方法

#[derive(Debug)] struct Person { name: String, age: u32, } // 实例方法 impl Person { // 如果不是&Self引用类型,则在对象调用此方法后,则对象已经被销毁,因为所有权机制,如果相对其修改则是&mut self fn say_my_name(self: &Self) { println!("name = {}", self.name) } // 此参数是上面的语法糖 fn say_my_age(&self) { println!("age = {}", self.age) } } // 实例方法, 可以多次impl一个struct来实现多个方法 impl Person { fn la_bb(&self, msg: &str) -> &str { print!("{msg} ~"); for _ in 0..self.age { print!("💩") } return " shuang"; } } // 关联方法 (静态方法) impl Person { fn cal(x: u32, y: u32) -> u32{ x + y } } fn main() { let person = Person { name: String::from("ohBug"), age: 20 }; person.say_my_age(); person.say_my_name(); let msg = person.la_bb("start ..."); println!("{msg}"); // 静态方法则用结构体名调用,与Java不同,Rust中person对象并不能调用cal,只能struct // let result = person::cal(2, 3); let result = Person::cal(1, 2); println!("{result}") } // output age = 20 name = ohBug start ... ~💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩 shuang 3
 

枚举

  • 枚举中的单个枚举被称为枚举类型的变体,不能对具体的单个变体进行impl操作。
    #[derive(Debug)] struct Person { name: String, age: u32, } // 枚举可以包罗万象 #[derive(Debug)] enum EveryThing { Person, Circle((i32, i32), i32), Open(bool), NoName, Dog { color: (i32, i32, i32), name: String, age: DogAge, }, } #[derive(Debug)] enum DogAge { OneYears = 1, // 给一个初始值1,后面依次递增 TwoYears, ThreeYears, } impl EveryThing { // 实例方法 match可有返回值也可没有,如下是对枚举进行解构 fn say(&self, msg: String) -> String { let type_msg = match self { Self::Person => "Person", Self::Circle((x, y), radius) => &format!("Circle radius = {radius}"), Self::Open(flag) => &format!("Open flag = {flag}"), Self::Dog { color, name, age } => &format!("Dog name = {name}"), _ => "others", // 匹配不到上面的默认处理 }; format!("{type_msg} {msg}") } } impl EveryThing { // 静态方法 fn view(target: &EveryThing) { println!("{:?}", target) } } fn main() { let person = Person { name: "ohBug".to_string(), age: 20, }; println!("person = {:?}", person); let person_everything = EveryThing::Person; println!("person_everyThing = {:?}", person_everything); let circle_everything = EveryThing::Circle((23, 12), 5); println!("circle_everything = {:?}", circle_everything); let dog_age = DogAge::ThreeYears; println!("dog_age = {:?}", dog_age); println!("dog_age = {:?}", dog_age as i32); let dog: EveryThing = EveryThing::Dog { color: (1, 2, 3), name: ("Berber".to_string()), age: DogAge::TwoYears, }; println!("dog = {:?}", dog); let dog_msg = dog.say("wangwang".to_string()); println!("dog_msg = {dog_msg}"); EveryThing::view(&dog); // :_ 指定方式可以忽略掉编译器的未使用的警告, 且后续不能够使用此变量 // 在解构的时候是可以进行重新命名的 let EveryThing::Dog {color, name: _, age: aaa} = dog else { panic!("not a dog"); }; println!("color = {:?}", color); // 后续不能够使用此变量 // println!("name = {name}"); println!("age = {:?}", aaa); } // output person = Person { name: "ohBug", age: 20 } person_everyThing = Person circle_everything = Circle((23, 12), 5) dog_age = ThreeYears dog_age = 3 dog = Dog { color: (1, 2, 3), name: "Berber", age: TwoYears } dog_msg = Dog name = Berber wangwang Dog { color: (1, 2, 3), name: "Berber", age: TwoYears } color = (1, 2, 3) age = TwoYears

    模式匹配

    • 就是按对象值的结构进⾏匹配。
    • 上面已经写了一些对枚举类型的对象进行解构。除了match可以进行解构外,还可以使用let。
    #[derive(Debug)] struct Person { name: String, age: u32, } fn main() { let person = Person { name: "ohBug".to_string(), age: 20, }; if let Person {name, age} = person { println!("is a person {name}"); }else { println!("not a person"); } } //output is a person ohBug
     
    #[derive(Debug)] struct Person { name: String, age: u32, } fn main() { let person = Person { name: "ohBug".to_string(), age: 20, }; // ref 是在模式匹配过程中提供⼀个额外的信息,告诉编译器只是需要读取⼀下字段的值⽽已, // 不需要获得它的所有权,ref带来的改变就是获取&person.name // 还有一个 ref mut 的形式,表示name可变,即可变引用。 if let Person {ref name, age} = person { println!("is a person {name}"); }else { println!("not a person"); } // 如果没有ref,则这里报错 let person_name = person.name; println!("{person_name}") }
     

    思考

    • 因为基础类型以及切片类型都是不具有所有权的类型, Rust 默认不会深度拷⻉数据,如果最后let c: String = *b; 成立,则意味着要夺⾛a的所有权。为了不被夺走所有权,则Rust直接阻止了这种方式,也给出了提示,除非所有权类型实现了`Copy` trait
    fn main() { let a: i32 = 3; let b: &i32 = &a; let c: i32 = *b; println!("{c}"); let a: &str = "3"; let b: &&str = &a; let c: &str = *b; println!("{c}"); let a: String = "3".to_string(); let b: &String = &a; let c: String = *b; // error: ^^ move occurs because `*b` has type `String` // , which does not implement the `Copy` trait println!("{c}"); }
    • 如下,由上面经验告诉我们解引用会带来所有权的转移,但是在枚举上self*self效果是一样的,且所有权并不会受到影响,这是因为在枚举match时只是对类型进行了匹配,并不会进行对负载的匹配捕获,因此不存在赋值操作,所以也就没有了所有权问题。进而跟copy trait也就没关系了。其match效果一样是Rust进行了自动的解引用操作。
    enum Animal { Cat,Dog } impl Animal { fn is(&self) { match self { Self::Cat => print!("cat"), Self::Dog => print!("dog"), } } fn isa(&self) { match *self { Self::Cat => print!("cat"), Self::Dog => print!("dog"), } } } fn main() { let dog = Animal::Dog; dog.is(); dog.isa(); dog.is(); } // output dogdogdog