rust 初探 – struct
定义和实例化 struct
定义 struct
示例:
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
实例化 struct
- 实例化的顺序可以不一样
- 但是必须给所有字段都赋值
一些操作方法
- 使用点标记法获取某个值:user1.email
- 一旦 struct 的实例是可变的,那么里面所有的字段都是可变的
- 字段初始化简写:当字段名和字段值对应变量名相同时,可以使用字段初始化简写
fn build_user(email: String, username: string) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
- 当基于某个 struct 实例来创建一个新实例的时候,使用更新语法:
let user2 = User {
email: String::from("user2_email"),
username: String::from("user2_name"),
active: use1.active,
sign_in_count: use1.sign_in_count,
};
let user2 = User {
email: String::from("user2_email"),
username: String::from("user2_name"),
..user1
};
- tuple struct: struct Color(i32, i32),不同名的是不同的数据类型
- Unit-Like Struct:没有任何字段的 struct,适用于需要在某个类型上实现某个 trait,但是在里面又没有想要存储的数据
struct 数据所有权
- 如果 struct 里面没有存放引用,那么 struct 实例拥有其所有的数据,只要 struct 是有效的,那么里面的字段数据也是有效的
- 如果存放了引用,那么就需要使用生命周期,生命周期保证只要 struct 实例是有效的,那么里面的引用也是有效的(否则报错)
struct 例子
// 这样子就可以未自定义的 struct 进行打印,因为自定义的没有实现 Display, Debug 的trait
#[derive(Debug)]
struct Rectangle {
width: u32,
length: u32,
}
fn main() {
let rec = Rectangle {
width: 20,
length: 10,
};
println!("{}", area(&rec));
println!("{:#?}", rec);
}
fn area(rec: &Rectangle) -> u32 {
rec.length * rec.width
}
struct 方法
相关定义
- 方法和函数类似:fn 关键字、名称、参数、返回值
- 方法和函数不同之处:
- 方法是在 struct 的上下文中定义
- 第一个参数是 self,表示方法被调用的 struct 实例
- 每个 struct 可以有多个 impl
#[derive(Debug)]
struct Rectangle {
width: u32,
length: u32,
}
// impl 声明块,在块里面定义方法
impl Rectangle {
// 上下文
// self 会自动推断为 Rectangle
// 可以是 &self,也可以获得其所有权或可变借用
// 这样会有更好的代码组织
fn area(&self) -> u32 {
self.length * self.width
}
}
fn main() {
let rec = Rectangle {
width: 20,
length: 10,
};
println!("{}", rec.area());
println!("{:#?}", rec);
}
方法调用的运算符
- Rust 会自动引用或者解引用:在调用方法的时候,会根据情况自动添加 &、&mut 或者 *,以便 object 可以匹配方法的签名
- p1.distance(&p2); 等效 (&p1).distance(&p2);
方法参数
- 除了 self,还可以添加其他参数,如 can_hold 函数:
#[derive(Debug)]
struct Rectangle {
width: u32,
length: u32,
}
// impl 声明块,在块里面定义方法
impl Rectangle {
// 上下文
// self 会自动推断为 Rectangle
// 可以是 &self,也可以获得其所有权或可变借用
// 这样会有更好的代码组织
fn area(&self) -> u32 {
self.length * self.width
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.length > other.length
}
}
fn main() {
let rec = Rectangle {
width: 20,
length: 10,
};
println!("{}", rec.area());
println!("{:#?}", rec);
let rec1 = Rectangle {
width: 10,
length: 5,
};
let rec2 = Rectangle {
width: 30,
length: 50,
};
println!("rec1 can hold: {}", rec.can_hold(&rec1));
println!("rec2 can hold: {}", rec.can_hold(&rec2));
}
关联函数
- 可以在 impl 块里定义不把 self 作为第一个参数的函数,它们叫做关联函数(不是方法)
- 关联函数通常用于构造器
#[derive(Debug)]
struct Rectangle {
width: u32,
length: u32,
}
// impl 声明块,在块里面定义方法
impl Rectangle {
// 上下文
// self 会自动推断为 Rectangle
// 可以是 &self,也可以获得其所有权或可变借用
// 这样会有更好的代码组织
fn area(&self) -> u32 {
self.length * self.width
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.length > other.length
}
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
length: size,
}
}
}
fn main() {
let s = Rectangle::square(3);
// :: 符号:用于关联函数,或者模块创建的命名空间
println!("{}", s.area());
println!("{:#?}", s);
let rec1 = Rectangle {
width: 10,
length: 5,
};
println!("s can hold: {}", rec1.can_hold(&s));
}