C5 Rust struct
- 定义和实例化struct
-
- 定义struct
- 实例化struct
- 取得struct里面的某个值
- 注意
- struct可以作为函数的返回值
- 字段初始化简写
- struct更新语法
- [Tuple struct](#Tuple struct)
- [Unit-Like Struct(没有任何字段)](#Unit-Like Struct(没有任何字段))
- struct数据的所有权
- [struct 例子](#struct 例子)
- [struct 方法](#struct 方法)
定义和实例化struct
定义struct
-
使用struct关键字,并为它命名
-
格式:
- 在花括号内,为所有字段(field)定义名称和类型
-
例子:
ruststruct User{ // 先写名称:再写类型 username:String, email:String, sign_in_count:u64, // 最后一个在现有的rust版本中好像不加,也可以了 active:bool, }
实例化struct
-
实例化struct(使用struct)
- 为每个字段指定具体的值
- 无需按照声明的顺序进行指定
-
例子
rustfn main(){ let user1 = User{ // 每个字段都要指定具体的值 username: String::from("Xiaoming"), // 顺序可以不一致 active: true, email: String::from("xiaoming@163.com"), sign_in_count:12, }; } struct User{ username:String, email:String, sign_in_count:u64, active:bool, }
取得struct里面的某个值
-
使用点标记法
rustuser1.email
注意
- 一旦struct的实例是可变的,那么实例中所有字段都是可变的
struct可以作为函数的返回值
-
例子
rustfn build_user(email: String, username:String) ->User{ return User{ email:email, username:username, active:true, sign_in_count:01, }; }
字段初始化简写
-
当字段名与字段值对应变量名相同时,可以使用字段初始化简写
rustfn main(){ let user2 = build_user(String::from("xiaohong@163.com"), String::from("xiaohong")); println!("email: {}, username: {}, active: {}, signInCount: {}", user2.email,user2.username, user2.active, user2.sign_in_count); } //函数传入参数名称和struct中定义的字段名称一样才可以简写 fn build_user(email: String, username:String) ->User{ return User{ email, username, active:true, sign_in_count:01, }; } struct User{ email:String, username:String, sign_in_count:u64, active:bool, }错误示范:

struct更新语法
-
基于已有的struct创建新的实例->使用struct更新语法
rustlet user3 = User{ username: String::from("Xiaoqiang"), email: String::from("Xiaoqiang@163.com"), sign_in_count: user1.sign_in_count, active: user1.active, };可以简写为
rustlet user1 = User{ username: String::from("Xiaoming"), active: true, email: String::from("xiaoming@163.com"), sign_in_count:12, }; let user3 = User{ username: String::from("Xiaoqiang"), email: String::from("Xiaoqiang@163.com"), // 表明剩下的两个字段直接使用user1的值 ..user1 };
Tuple struct
-
定义类似tuple的struct,叫做tuple struct
- tuple struct 整体有名字,但里面元素没有名字
- 适用:相关整个tuple起名字,都是又不需要给各个元素起名字
-
如何定义 tuple struct
- struct tuple名称(元素类型, 元素类型, 元素类型);
- 例子:
ruststruct Color(i32,i32,i32); struct Point(i32,i32,i32); let black = Color(0,0,0); let origin_point = Point(0,0,0);- Color和Point都叫tuple struct,是不同的类型
Unit-Like Struct(没有任何字段)
- 一个没有任何字段的struct
- 适用于需要实现某个类型上的trait,但是里面没有想要存储的数据
struct数据的所有权
rust
struct User{
username:String,
email:String,
sign_in_count:u64,
active:bool,
}
- 字段使用了String而不是&str
- 该struct拥有String字段的所有数据
- 只有struct是有效的,里面的字段数据也是有效的
- struct中可以存放引用,但是需要使用生命周期(以后会学)
- 声明周期保证只有struct实例是有效的,里面的引用也是有效的
- 如果struct直接存储引用,但是不用生命周期会报错

struct 例子
计算长方形面积的实现
- 需求:计算长方形面积
- 初级:使用函数参数
rust
fn main(){
let w = 30;
let l = 50;
println!("Area: {}", area(w, l));
}
fn area(width:u32, length:u32)->u32
{
return width*length;
}
缺点:看起来w和l没有关联
- 使用tuple
rust
fn main(){
let w = 30;
let l = 50;
println!("Area: {}", area((w,l)));
}
// 使用tuple
fn area(dim:(u32,u32))->u32
{
return dim.0*dim.1;
}
缺点:长和宽虽然有关联了,但是没有名称了,可读性很差
- 使用struct + 函数实现
rust
fn main(){
let r1 = Rectangle{
width:12,
length:9,
};
let area = area(&r1);
println!("Area: {}", area);
}
struct Rectangle{
width:u32,
length:u32,
}
fn area(rect: &Rectangle)->u32
{
return rect.width*rect.length;
}
优点: 长宽联系起来了且长宽有名字
输出一个struct
-
想直接print r1这个struct
-
结果会报错

-
建议使用
{:?}或者 {:#?} ,但是加了之后还是会报错,报错是和debug有关

-
添加
#[derive(Debug)]和{:?}或者{:#?}{:?}和{:#?}的区别{:?}是返回单行:
Rectangle { width: 12, length: 9 }{:#?}是返回有格式的,结构更清晰:
Rectangle {
width: 12,
length: 9,
}

-
-
总结struct相关
- std::fmt::Display
- std::fmt::Debug
- #[derive(Debug)]
- {:?}
- {:#?}
struct 方法
方法
- 与函数的比较
- 和函数类似:fn关键字/名称/参数/返回值
- 和函数的不同点:
- 方法是在struct(或者enum/trait对象)的上下文中定义
- 方法的第一个参数是
&self,表示方法被调用的struct实例
- 上一个函数的缺点:单独的area函数很特殊,只适用于长方形,不适用于其他形状或者其他类型
- ->将area函数和struct Rectangle关联到一起是最好的
- 将原有的函数改成struct上定义的方法
- 方法的定义和调用
- 关键字
impl - 方法的第一个参数是
&self - 方法的调用:实例.函数名称() // 不需要显式的传入参数
- 在调用方法时,rust根据情况自动添加&/&mut/*,以便于object可以匹配方法的签名
r1.area()和(&r1).area()等效
- 关键字
rust
fn main(){
let r1 = Rectangle{
width:12,
length:9,
};
// 方法的调用:实例.函数名称
let area = r1.area();
println!("Area: {}", area);
println!("{:#?}", r1);
}
#[derive(Debug)]
struct Rectangle{
width:u32,
length:u32,
}
// struct的方法
impl Rectangle{
fn area(&self)->u32
{
return self.width*self.length;
}
}
- 方法可以有多个参数,但是第一个必须是`&self`
rust
impl Rectangle{
fn area(&self)->u32
{
return self.width*self.length;
}
// 多个参数
fn can_hold_another_rectangle(&self, other_rectangle: &Rectangle) -> bool
{
return self.width > other_rectangle.width && self.length > other_rectangle.length;
}
}

- 上面这个叫关联函数,见下
关联函数
-
关联函数:在impl块中定义不把self作为第一个参数的函数
- (不是方法)
- 不是在实例上调用的(我感觉像static)
- 通常用于构造器->创建一个被关联类型的实例
- 例子:String::from("xxx")
-
关联函数的调用:类型名::函数名
注意区别方法的调用和关联函数的调用的区别rust#[derive(Debug)] struct Rectangle{ width:u32, length:u32, } fn main(){ let r1 = Rectangle{ width:12, length:9, }; // 方法的调用:实例.函数名称 let area = r1.area(); println!("Area: {}", area); //关联函数的调用 let square = Rectangle::square(30); println!("{:#?}", square); } impl Rectangle{ // 方法 fn area(&self)->u32 { return self.width*self.length; } // 关联函数 fn square(size: u32) -> Rectangle { return Rectangle { width: size, length: size }; } }
多个impl块
- 每个struct允许拥有多个impl块
2026/1/7