rust_learning/struct_def.rs
1struct User {
2 username: String,
3 email: String,
4 sign_in_count: u64,
5 active: bool,
6}
7
8/// 结构体
9pub fn struct_def() {
10 // 实例化结构体
11 let user = User {
12 email: String::from("someone@example.com"),
13 username: String::from("someusername123"),
14 active: true,
15 sign_in_count: 1,
16 };
17
18 // 可变结构体
19 // 注意所有权的移动,所以在 user2 中,user的username 和 email 的所有权已经移动到 user2 中。
20 let mut user2 = User {
21 email: String::from("sometwo@example.com"),
22 // 结构体更新语法
23 ..user
24 };
25 user2.active = false;
26 // value borrowed here after move
27 // println!("{}", user.username);
28 let user3 = struct_build_user(String::from("some3"), String::from("some3@example.com"));
29}
30
31fn struct_build_user(username: String, email: String) -> User {
32 // 当变量的名称与结构体字段名称相同时,可以使用简写语法,也可以写完整
33 User {
34 username,
35 email,
36 active: true,
37 sign_in_count: 1,
38 }
39}
40
41#[derive(Debug)]
42struct Color(i32, i32, i32);
43#[derive(Debug)]
44struct Point(i32, i32, i32);
45
46/*
47 元组结构体(tuple structs)。
48*/
49/// 元组结构体
50pub fn tuple_struct() {
51 // 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。
52 // 当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,
53 let black = Color(0, 0, 0);
54 println!("{:#?}", black);
55 let origin = Point(0, 0, 0);
56 println!("{:#?}", origin);
57}
58
59// struct 没有字段
60// 类单元结构体
61// 类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。
62struct AlwaysEqual;
63fn struct_no_field() {
64 let subject = AlwaysEqual;
65}
66
67
68#[derive(Debug)]
69struct Rectangle {
70 width: u32,
71 height: u32,
72}
73// 所有在 impl 块中定义的函数被称为 关联函数(associated functions),因为它们与 impl 后面命名的类型相关。
74// 不是方法的关联函数经常被用作返回一个结构体新实例的构造函数。这些函数的名称通常为 new ,但 new 并不是一个关键字。
75impl Rectangle {
76 // 我们并不想获取所有权,只希望能够读取结构体中的数据,而不是写入。
77 // 如果想要在方法中改变调用方法的实例,需要将第一个参数改为 &mut self。
78 // 通过仅仅使用 self 作为第一个参数来使方法获取实例的所有权是很少见的;
79 // 这种技术通常用在当方法将 self 转换成别的实例的时候,这时我们想要防止调用者在转换之后使用原始的实例。
80
81 //通常,但并不总是如此,与字段同名的方法将被定义为只返回字段中的值,而不做其他事情。
82 // 这样的方法被称为 getters,Rust 并不像其他一些语言那样为结构字段自动实现它们。
83 // Getters 很有用,因为你可以把字段变成私有的,但方法是公共的,这样就可以把对字段的只读访问作为该类型公共 API 的一部分。
84
85 // Rust 有一个叫 自动引用和解引用(automatic referencing and dereferencing)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。
86 // 它是这样工作的:当使用 object.something() 调用方法时,Rust 会自动为 object 添加 &、&mut 或 * 以便使 object 与方法签名匹配。也就是说,这些代码是等价的:
87 //
88 //
89 // p1.distance(&p2);
90 // (&p1).distance(&p2);
91
92 // 在给出接收者和方法名的前提下,Rust 可以明确地计算出方法是仅仅读取(&self),做出修改(&mut self)或者是获取所有权(self)。
93 fn area(&self) -> u32 {
94 self.width * self.height
95 }
96}
97
98impl Rectangle {
99 fn can_hold(&self, other: &Rectangle) -> bool {
100 self.width > other.width && self.height > other.height
101 }
102}
103
104/// 方法
105pub fn struct_method() {
106 let rect1 = Rectangle {
107 width: dbg!(30),
108 height: 50,
109 };
110 // 另一种使用 Debug 格式打印数值的方法是使用 dbg! 宏。
111 // dbg! 宏接收一个表达式的所有权(与 println! 宏相反,后者接收的是引用),打印出代码中调用 dbg! 宏时所在的文件和行号,
112 // 以及该表达式的结果值,并返回该值的所有权。
113 // 注意:调用 dbg! 宏会打印到标准错误控制台流(stderr),与 println! 不同,后者会打印到标准输出控制台流(stdout)。
114 dbg!(&rect1);
115 println!(
116 "The area of the rectangle is {} square pixels.",
117 rect1.area()
118 );
119
120
121 let rect2 = Rectangle {
122 width: 10,
123 height: 40,
124 };
125
126 let rect3 = Rectangle {
127 width: 60,
128 height: 45,
129 };
130
131
132 println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
133}