如何做电商网站视频,项目管理软件手机版,兰州做网站的,网站备案后可以修改吗目录
结构体#xff08;Struct#xff09;
定义与声明
结构体定义
结构体实例
结构体分类
单元结构体#xff08;Unit Struct#xff09;
元组结构体#xff08;Tuple Struct#xff09;
具名结构体#xff08;Named Struct#xff09;
结构体嵌套
结构体方法…
目录
结构体Struct
定义与声明
结构体定义
结构体实例
结构体分类
单元结构体Unit Struct
元组结构体Tuple Struct
具名结构体Named Struct
结构体嵌套
结构体方法
例1结构体转换为字符串描述
例2矩形的周长和面积
例3结构体字段的更新与输出
关联函数
结构体方法与关联函数的区别
参数传递方式的区别
使用方式的区别
结构体的trait
#[derive(Debug)]
例1
例2
自定义打印宏
1. impl fmt::Debug for Student
2. impl fmt::Display for Student
#[derive(PartialEq)]
例1
例2
#[derive(Default)]
例1
例2
#[derive(Clone)]
其他相关内容
模式匹配
例1
例2
结构体大小
1. std::mem::size_of
2. std::mem::size_of_val
本文总结 结构体Struct
是一种自定义数据类型允许将多个相关的值组合在一起形成一个更复杂的数据结构。结构体被广泛应用于组织和管理数据具有灵活性和强大的表达能力。
定义与声明
结构体定义
在Rust中定义和声明结构体的语法如下
struct Name { field1: Type1, field2: Type2, // ... fieldN: TypeN,
}
其中Name是结构体的名称每个数据名及其对应的数据类型组成一个字段field1到fieldN是结构体的字段名称Type1到TypeN是字段的数据类型。
通过关键字 struct 定义指定结构体名称结构体内用 field:type, 表示字段名称及数据类型注意rust语言不能在定义的同时进行赋值且用逗号分隔各字段不像c/c用分号。
结构体中可以根据需要定义字段个数理论上要多少就定义多少但实际上字段太多结构体也会变得很占空间对程序的空间效率是个负担。
结构体实例
如以下代码定义了一个名为Point的结构体包含x和y两个字段类型分别为i32和f64
struct Point { x: i32, y: f64, }
定义结构体后可以像使用其他类型一样使用它。例如可以声明一个Point类型的变量并为其字段赋值
let my_point Point { x: 10, y: 20.0 };
使用结构体时用成员运算符 my_point.x 来调用对应字段的值
println!(({},{}), point.x, point.y); // 输出(10,20)
可变实例
需要变动字段的值在声明时需要用 let mut如
struct Point { x: i32, y: f64,
}fn main() {let mut point Point { x: 10, y: 20.0 }; point.x 5;println!(({},{}), point.x, point.y); // 输出(5,20)
}
结构体分类
在Rust中结构体Struct可以按照不同的方式进行分类以下是一些常见的分类方式
单元结构体Unit Struct
这种结构体没有任何字段它只是用于表示一个空的类型。这种结构体通常用于作为其他结构体的组成部分或返回类型。例如
struct UnitStruct;
元组结构体Tuple Struct
这种结构体包含一组字段可以通过元组语法来访问每个字段。元组结构体可以用于表示简单的数据集合不使用大括号{}而是使用元组的小括号()。例如
struct TupleStruct(i32, String);
相当字段数据没有名称的结构体访问时使用索引。如
struct Point (i32, f64);fn main() {let mut point Point(10, 20.0); point.0 5;println!(({},{}), point.0, point.1);
}
具名结构体Named Struct
这种结构体有一个显式的名称并且包含一组字段。具名结构体可以用于表示复杂的数据结构例如一个包含多个字段的对象本文的示例大多数都为具名结构体用法已在本文开头讲过
struct MyStruct { field1: i32, field2: String, // ... }
除了以上三种常见的结构体类型Rust还支持其他特殊类型的结构体例如带有泛型参数的结构体、具名元组结构体Named Tuple Struct和结构体路径Struct Type Alias等。
需要注意的是在Rust中结构体的分类并不是强制性的也就是说一个结构体可以包含任意类型的字段并且可以在任何地方使用。这使得结构体非常灵活可以用于实现各种复杂的数据结构。
结构体字段的数据类型可以是以下常见的rust数据甚至可以是函数、引用、指针类型。 标量类型Scalar Types 整数类型Integer Types包括有符号整数类型和无符号整数类型。常见的整数类型有 i8、i16、i32、i64、i128 表示有符号整数u8、u16、u32、u64、u128 表示无符号整数。此外还有 isize 和 usize它们根据平台的位数自动调整大小。浮点数类型Floating-Point Number Types包括 f32 和 f64 两种类型表示单精度和双精度浮点数。布尔类型Boolean Type只有两个取值true 和 false。字符类型Character Type表示单个 Unicode 字符通常存储为 4 个字节。 复合类型Composite Types 数组类型Array Types由相同类型的元素组成的有限集合。可以通过固定长度或动态长度来定义数组。切片类型Slice Types对一个连续的内存块进行引用可以看作是动态数组。切片类型提供了访问和操作数据的一种高效方式。元组类型Tuple Types一种将多个不同类型的值组合在一起的数据结构用圆括号和逗号分隔的元素序列表示。元组可以包含不同类型的元素例如整数、浮点数、布尔值、字符串等。结构体类型Struct Types一种自定义的数据类型可以包含多个不同类型的字段。结构体可以通过定义来指定其字段和属性。枚举类型Enum Types表示一个可能取多个值的变量。在 Rust 中枚举类型使用 enum 关键字定义每个可能的取值都是一个不同的枚举成员。
结构体嵌套
一个结构体可以包含任意类型的字段当然也包括结构体。
在以下这个例子中Address 结构体包含了 street、city 和 state 三个字段而 Person 结构体则包含了 name、age 和 address 三个字段其中 address 字段的类型是 Address 结构体。
struct Address { street: String, city: String, state: String,
} struct Person { name: String, age: u8, address: Address,
}
结构体方法
方法method是在结构体上定义的功能可以访问结构体的字段并执行一些操作。使用关键字impl结构体可以对应一个或多个impl代码块。
例1结构体转换为字符串描述
struct Student {name:String,age:u32,school:String,major:String,grade:String,state:bool
}impl Student { fn to_string(self) - String { format!(Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }}, self.name, self.age, self.school, self.major, self.grade, self.state) }
} fn main() {let school String::from(东南大学);let major String::from(土木工程学院);let s Student{name:String::from(杨程),age:22,school,major,grade:String::from(大三),state:true};println!({}, s.to_string());
}
输出
Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }
注意上例中有一个rust结构体的特殊用法使用同名变量在结构体外为对应字段赋值。
例2矩形的周长和面积
struct Rectangle { width: f32, height: f32,
} impl Rectangle { // 构造函数 fn new(width: f32, height: f32) - Rectangle { Rectangle { width, height } } // 计算矩形的面积 fn area(self) - f32 { self.width * self.height } // 计算矩形的周长 fn perimeter(self) - f32 { (self.width self.height) * 2.0}
}impl Rectangle { // 判断矩形是否相等 fn is_equal(self, other: Rectangle) - bool { self.width other.width self.height other.height }
} fn main() { let rect1 Rectangle::new(5.0, 6.0); let rect2 Rectangle::new(5.0, 6.0); println!(Rectangle 1 area: {}, rect1.area()); println!(Rectangle 1 perimeter: {}, rect1.perimeter()); println!(Rectangle 2 area: {}, rect2.area()); println!(Rectangle 2 perimeter: {}, rect2.perimeter()); if rect1.is_equal(rect2) { println!(Rectangles are equal); } else { println!(Rectangles are not equal); }
}
输出
Rectangle 1 area: 30 Rectangle 1 perimeter: 22 Rectangle 2 area: 30 Rectangle 2 perimeter: 22 Rectangles are equal
例3结构体字段的更新与输出
struct Person { name: String, age: u32,
} impl Person { // 这是构造函数用于创建一个新的 Person 实例 fn new(name: String, age: u32) - Person { Person { name, age } } fn say_hello(self) { println!(Hello, my name is {} and Im {}., self.name, self.age); } fn update_age(mut self, new_age: u32) { self.age new_age; } fn update_name(mut self, new_name: String) { self.name new_name; }
} fn main() { // 创建一个新的 Person 实例 let mut person Person::new(Tom.to_string(), 5); // 调用 say_hello 方法输出 Person 的信息 person.say_hello(); // 调用 update_age 方法更新 Person 的年龄 person.update_age(3); // 再次调用 say_hello 方法输出更新后的信息 person.say_hello(); person.update_age(5);person.update_name(String::from(Jerry)); person.say_hello();
}
输出
Hello, my name is Tom and Im 5. Hello, my name is Tom and Im 3. Hello, my name is Jerry and Im 5.
关联函数
之所以结构体方法不叫结构体函数是因为函数这个名字留给了这种函数它在 impl 块中却没有 self 参数。这种函数不依赖实例但是使用它需要声明是在哪个 impl 块中的比如上小节例2和例3中的构造函数new()就是关联函数类似于字符串函数String::new()String::from(Jerry)。
示例
#[derive(Debug,Clone)]
struct Rectangle {width: u32,height: u32,
}impl Rectangle {fn create(width: u32, height: u32) - Rectangle {Rectangle { width, height }}fn area(self) - u32 {self.width * self.height}fn area2(self) - u32 {self.width * self.height}
}fn main() {let rect Rectangle::create(30, 50);println!({:?}, rect);println!(Area: {}, Rectangle::area(rect.clone()));println!(Area: {}, rect.area2());
}
输出
Rectangle { width: 30, height: 50 } Area: 1500 Area: 1500
结构体方法与关联函数的区别
参数传递方式的区别
结构体方法结构体方法默认情况下是可变的mutable也就是说可以修改结构体的字段。在调用方法时可以通过引用self或可变引用mut self来传递结构体实例以便修改其字段。例如my_struct.my_method(mut my_struct)。
关联函数关联函数默认情况下是不可变的immutable也就是说无法修改结构体的字段。在调用函数时只能通过常量引用self来传递结构体实例因为常量引用是只读的。例如let my_struct MyStruct {...}; my_struct.my_function()。
使用方式的区别
结构体方法结构体方法可以直接在结构体实例上调用无需显式传递结构体实例。例如my_struct.my_method()。
关联函数关联函数需要显式传递结构体实例作为参数。例如MyStruct::my_function(my_struct)。
结构体的trait
Rust 中的 trait 是一种抽象类型用于定义泛型行为trait 可以理解为一种接口。trait 使用关键字 derive 来自动生成实现。通过使用 derive可以避免手动编写冗长的代码提高代码的可读性和可维护性。trait 有很多比如CopyCloneDebugDefaultDropHashOrdPartialOrdSendSync等等先挑几种最常用的学一下
#[derive(Debug)]
在 Rust 语言中用于自动生成一个结构体的 Debug 实现Debug 是 Rust 标准库中的一个 trait用于在控制台打印调试信息。
使用 #[derive(Debug)] 属性可以为结构体自动生成一个 Debug 实现这样在需要打印调试信息时就可以使用 {:?} 格式化字符串来打印该结构体的内容。例如在上面的代码中s 结构体的 Debug 实现已经被自动生成因此可以使用 println!({:?}, s) 来打印出结构体 s 的内容。
例1
#[derive(Debug)]
struct Point {x: i32,y: i32,
}impl Point {fn distance(self, other: Point) - f32 {let x_diff self.x - other.x;let y_diff self.y - other.y;((x_diff * x_diff y_diff * y_diff) as f32).sqrt()}
}fn main() {let p1 Point { x: 3, y: 0 };let p2 Point { x: 0, y: 4 };println!(Distance between {:?} and {:?} is {}., p1, p2, p1.distance(p2));
}
输出
Distance between Point { x: 3, y: 0 } and Point { x: 0, y: 4 } is 5.
例2
#[derive(Debug)]
struct Student {name: String,age: u32,school: String,major: String,grade: String,state: bool,
} impl Student {fn new() - Student {return Student {age: 0,name: String::new(),school: String::from(),major: .to_string(),grade: .to_string(),state: false,};}
}fn main() { let mut s Student::new();s.name String::from(杨程);s.age 22;s.school String::from(东南大学);s.major String::from(土木工程学院);s.grade String::from(大三);s.state true;println!({:?}, s);
}
输出
Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }
与上一小节的例2对比输出内容基本一致就多了String的引号标记。相比自动生成 Debug 实现可以简化代码编写过程并且可以避免手动实现 Debug 时可能出现的错误。
在本例中使用宏打印结构体println!({:?}, s);时第一行的代码#[derive(Debug)]是必须的如果去掉就会报错 error[E0277]: Student doesnt implement Debug -- E:\.rs\struct2.rs:31:22 | 31 | println!({:?}, s); | ^ Student cannot be formatted using {:?} | help: the trait Debug is not implemented for Student note: add #[derive(Debug)] to Student or manually impl Debug for Student note: this error originates in the macro $crate::format_args_nl which comes from the expansion of the macro println (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating Student with #[derive(Debug)] | 1 #[derive(Debug)] 2 | struct Student { | error: aborting due to previous error 自定义打印宏
1. impl fmt::Debug for Student
返回值fmt::Result 调用println!({:?}, s);
use std::fmt;struct Student {name: String,age: u32,school: String,major: String,grade: String,state: bool,
} impl fmt::Debug for Student { fn fmt(self, f: mut fmt::Formatter_) - fmt::Result {write!(f,Student {{ name: {}, age: {}, school: {}, major: {}, grade: {}, state: {} }},self.name, self.age, self.school, self.major, self.grade, self.state)}
} fn main() { let school String::from(东南大学);let major String::from(土木工程学院);let s Student {name: String::from(杨程),age: 22,school,major,grade: String::from(大三),state: true,}; println!({:?}, s);
}
输出
Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true }
2. impl fmt::Display for Student
返回值fmt::Result 调用println!({}, s); {}里不需要:?
use std::fmt;struct Point {x: i32,y: i32,
}impl fmt::Display for Point {fn fmt(self, f: mut fmt::Formatter) - fmt::Result {write!(f, ({}, {}), self.x, self.y)}
}impl Point {fn distance(self, other: Point) - f32 {let x_diff self.x - other.x;let y_diff self.y - other.y;((x_diff * x_diff y_diff * y_diff) as f32).sqrt()}
}fn main() {let p1 Point { x: 3, y: 0 };let p2 Point { x: 0, y: 4 };println!(Distance between {} and {} is {}., p1, p2, p1.distance(p2));
}
输出
Distance between Point(3, 0) and Point(0, 4) is 5.
输出要与使用#[derive(Debug)]时一样只要修改write宏的第2个参数如
impl fmt::Display for Point {fn fmt(self, f: mut fmt::Formatter) - fmt::Result {write!(f, Point {{ x: {}, y: {} }}, self.x, self.y)}
}
#[derive(PartialEq)]
使用#[derive(PartialEq)]为结构体自动实现了PartialEq trait。这使得可以直接使用运算符比较两个结构体实例的相等性。
例1
#[derive(PartialEq)]
struct Point { x: i32, y: i32,
}fn main() {let point1 Point { x: 10, y: 20 }; let point2 Point { x: 10, y: 20 }; if point1 point2 { println!(The two points are equal.); } else { println!(The two points are not equal.); }
}
输出
The two points are equal.
例2
#[derive(Debug, PartialEq)]
struct Person {name: String,age: u32,
}fn main() {let person1 Person {name: String::from(Alice),age: 25,};let person2 Person {name: String::from(Bob),age: 30,};let person3 Person {name: String::from(Alice),age: 25,};println!(Is {:?} equal to {:?}? {}, person1, person2, person1 person2);println!(Is {:?} equal to {:?}? {}, person1, person3, person1 person3);
}输出
Is Person { name: Alice, age: 25 } equal to Person { name: Bob, age: 30 }? false Is Person { name: Alice, age: 25 } equal to Person { name: Alice, age: 25 }? true
#[derive(Default)]
调用#[derive(Default)]相当于创建一个默认的结构体实例每一个字段都是对应数据类型的默认值无需手动为每个字段设置默认值。
例1
#[derive(Default,Debug)]
struct Circle {radius: f32,
} impl Circle {fn area(self) - f32 {let pi std::f32::consts::PI;pi * self.radius * self.radius}
}fn main() {let mut c Circle::default();println!(Circular area of {:?} {}., c, c.area());c.radius 1.0;println!(Circular area of {:?} {}., c, c.area());
}
输出
Circular area of Circle { radius: 0.0 } 0. Circular area of Circle { radius: 1.0 } 3.1415927.
例2
#[derive(Debug, Default)]
struct Student { name: String, age: u32, school: String, major: String, grade: String, state: bool,
} fn main() { let mut s1 Student::default(); println!({:?}, s1);s1.name String::from(杨程); s1.age 22; s1.school String::from(东南大学); s1.major String::from(土木工程学院); s1.grade String::from(大三); s1.state true; println!({:?}, s1); let s2 Student { age: 23, grade: String::from(大四), ..s1 //注意这里的结构体更新语法}; println!({:?}, s2);
}
输出
Student { name: , age: 0, school: , major: , grade: , state: false } Student { name: 杨程, age: 22, school: 东南大学, major: 土木工程学院, grade: 大三, state: true } Student { name: 杨程, age: 23, school: 东南大学, major: 土木工程学院, grade: 大四, state: true }
此例还有一个rust结构体的特殊用法当结构体大部分字段需要被设置成与现存的另一个结构体的一样仅需更改其中的一两个字段的值可以使用结构体更新语法在现存的结构体名前加上两个连续的句号“..Struct_Name”。
#[derive(Clone)]
Clone 在复制过程中对所有字段进行逐个复制包括所有引用类型和原始类型。这意味着每次进行克隆时都会创建新的数据副本。
示例
#[derive(Clone)]
struct Person { name: String, age: i32,
} fn main() { let mut person1 Person { name: String::new(), age: 0 }; let mut person2 person1.clone();person1.name Alice.to_string();person1.age 22;println!(Person 1: {}, {}, person1.name, person1.age);println!(Person 2: {}, {}, person2.name, person2.age);person2 person1.clone();println!(Person 2: {}, {}, person2.name, person2.age);
}输出
Person 1: Alice, 22 Person 2: , 0 Person 2: Alice, 22
其他相关内容
模式匹配
结构体可用 模式匹配Pattern Matching来解构和访问其字段。
例1
struct Point {x: i32,y: i32,
}fn main() {let p Point { x: 10, y: 20 };match p {Point { x, y } {println!(x:{}, y: {}, x, y);}}
}
例2
struct Time { hour: i32, minute: i32, second: i32,
} fn main() { let t Time { hour: 10, minute: 30, second: 45 }; match t { Time { hour, minute, second } { print!(The time is {}:, hour);println!({}:{}, minute, second); } }
}
结构体大小
结构体的大小在C/C中使用运算符 sizeof 来计算在Rust语言中则使用标准库中的一个模块std::mem::中的size_of和size_of_val它提供了与内存管理相关的函数。
1. std::mem::size_of
用于计算给定类型的大小不接受任何参数。这个函数返回一个给定类型的大小以字节为单位。它是一个泛型函数可以用于任何类型。
示例
#![allow(dead_code)]struct Point {x: i32,y: i32,
} struct Person {name: String,age: i32,height: f32,is_employed: bool,
} fn main() {let point Point { x: 10, y: 20 }; println!(Size of Point: {}, std::mem::size_of::Point());let person Person {name: Hann Yang.to_string(),age: 50,height: 1.72,is_employed: true,}; println!(Size of Person: {}, std::mem::size_of::Person());
}
输出
Size of Point: 8 Size of Person: 40
2. std::mem::size_of_val
用于计算给定值的大小接受一个值作为参数。它用于获取一个值的大小以字节为单位。与 size_of 函数不同的是size_of_val 函数可以用于任何值而非类型。
示例
#![allow(dead_code)]struct Point {x: i32,y: i32,
} struct Person {name: String,age: i32,height: f32,is_employed: bool,
} fn main() {let point Point { x: 10, y: 20 }; println!(Size of Point: {}, std::mem::size_of_val(point));let person Person {name: Hann Yang.to_string(),age: 50,height: 1.72,is_employed: true,}; println!(Size of Person: {}, std::mem::size_of_val(person));
}
输出
Size of Point: 8 Size of Person: 40
注意在这两个例子中计算类型大小和值大小的结果都是相同的因为这里没有涉及到指针或其他复杂的情况。 本文总结
结构体是Rust中一种重要的数据结构用于组织不同类型的字段。以下是结构体的重点内容的总结
结构体定义使用struct关键字来定义结构体结构体可以包含多个字段每个字段可以有不同的类型。结构体实例定义一个结构体后可以使用结构体名称来创建结构体实例通过.运算符来访问结构体字段。结构体分类结构体可以分为三种类型单元结构体()、元组结构体用逗号分隔的多个字段和具名结构体有自定义名称的字段。结构体嵌套结构体可以嵌套用于组织和存储复杂的数据。结构体方法结构体可以定义方法用于在结构体上执行操作。结构体方法与关联函数类似但只能在结构体上调用。关联函数通过impl关键字在结构体上定义关联函数用于在结构体实例上执行特定操作。关联函数可以是普通函数或方法。自定义打印宏使用derive(Debug)]来自动实现fmt::Debug trait实现自定义的打印输出格式。其他相关内容结构体可以通过derive属性来自动实现其他trait如PartialEq部分相等性、Default默认值和Clone克隆。结构体大小在Rust中结构体的内存大小是固定的可以在定义时指定大小也可以使用#[repr(C)]来指定大小和布局。模式匹配可以使用模式匹配来访问和匹配结构体的字段这使得在编写代码时更加灵活和方便。
总的来说结构体是Rust中非常强大和灵活的数据结构可以用于组织和操作各种类型的数据。通过使用结构体、方法、关联函数和其他相关特性可以轻松地实现复杂的数据结构和算法。