结构体
命名结构体 named struct
named struct 和 Golang 的 struct 类似。
定义结构体:
| struct 结构体名 {
字段名: 类型,
字段名: 类型,
......
}
|
构造结构体实例:
| let 实例名 = 结构体名{
字段名: 值,
字段名: 值,
......
}
let 实例名 = 结构体名{
值,
值,
......
}
let 实例名2 = 结构体名{
字段名: 值,
字段名: 值,
..实例名1
}
|
实例化结构体时,可以写出字段,这样赋值可以不按照定义时的字段的顺序,也可以不写出字段,但这样必须按照定义时的字段顺序。
除此之外还可以使用 ..其他实例名
的方式借用或拷贝其他实例剩余字段的值。
Warning
注意 Rust 的结构体在构造时需给所有字段赋值。
使用第三种方式的时候,如果被拷贝的实例的字段不是可拷贝的,那么它的所有权会被移到新的结构体上。
| struct Person{
name: String,
age u32,
}
fn main() {
let s1 = Person{
name: String::from("Boii");
age: 18,
};
let s2 = Person{
..s1
}
println!("{}", s2.age); // 18
println!("{}", s2.name); // Boii
println!("{}", s1.age); // age 是可拷贝的,所以 s1.age 不会失去所有权
println!("{}", s1.name); // s1 的 name 字段已经被移到 s2.name 上了,所以这里 s1.name 已经变成为初始化的状态,打印她会报错
}
|
如果不希望 s1 失去所有权,可以使用 .clone()。
| fn main() {
let s1 = Person{
name: String::from("Boii");
age: 18,
};
let s2 = Person{
..s1.clone() // 使用克隆
}
println!("{}", s2.age); // 18
println!("{}", s2.name); // Boii
println!("{}", s1.age); // age 是可拷贝的,所以 s1.age 不会失去所有权
println!("{}", s1.name); // s1 的 name 字段只是被克隆,所以这里 s1.name 依然不变,可以正常使用
}
|
元组结构体 tuple struct
除了 named struct 之外, Rust 提供了一种 tuple struct (元组结构体),非常适合一些少量字段的结构。
例如颜色、坐标:
| struct Color(u8, u8, u8);
struct Point2d(f64, f64);
|
| let red = Color(0xFF, 0, 0);// 赋值
let Color(r, g, b) = red; // 解构
|
空结构体 unit-like struct
结构体内部可以没有任何字段,这样的结构体实例内存占用为 0,但定义后面不可以加大括号(除了1.9 nightly)。
但我们可以对空结构体实现她的成员函数。
| struct emptySt;
let empty = emptySt;
impl someTrait for emptySt {
...
}
|
当我们只想关心该类型的行为,不想关心该类型的内容时,就非常适合使用空结构体。
struct 的方法
定义 struct 方法使用 impl STRUCT_NAME{}
,形式如下:
| impl STRUCT_NAME {
<METHOD SET>
...
}
|
Example
| struct Person {
name: String,
age: u32,
}
impl Person { // 定义结构体 Person 的方法
fn get_name(&self) -> &str {
&self.name
}
fn get_age(&self) -> u32 {
self.age
}
}
fn main() {
let person = Person {
name: "Boii".to_string(),
age: 18,
};
println!("name: {:?}", person.get_name());
println!("age: {:?}", person.get_age());
}
|
可以将多个方法定义在多个 impl STRUCT_NAME{}
块中
self、&self、&mut self
self
表示结构体实例的所有权转移到该方法中,这种形式较少,因为这会使得调用方法后对象立即消失。但有时候也能派上场,例如可用于替换对象:调用方法后原对象消失,但返回另一个替换后的对象。;
&self
表示该方法对结构体实例的不可变借用;适用于 getter;
&mut self
表示方法对结构体的可变借用;适用于 setter;
| struct Person {
name: String,
age: u32,
}
impl Person {
fn get_name(&self) -> &str {
self.name.as_str()
}
fn get_age(&self) -> u32 {
self.age
}
fn set_name(&mut self, name: &str) {
self.name = String::from(name);
}
fn set_age(&mut self, age: u32) {
self.age = age;
}
}
fn main() {
let mut p1 = Person {
name: "Boii".to_string(),
age: 18,
};
println!("name: {:?}", p1.get_name()); // name: "Boii"
println!("age: {:?}", p1.get_age()); // age: 18
p1.set_age(20);
p1.set_name("Eva");
println!("name: {:?}", p1.get_name()); // name: "Eva"
println!("age: {:?}", p1.get_age()); // age: 20
}
|
字段同名方法
Rust 允许实现与字段名同名的方法。加上括号则是调用方法,没有括号则是调用字段。
| struct Person {
name: String,
age: u32,
}
impl Person {
fn name(&self) -> &str {
"method: " + self.name.as_str()
}
fn age(&self) -> u32 {
"age: " + self.age
}
}
fn main() {
let p1 = Person {
name: "Boii".to_string(),
age: 18,
};
println!("name: {:?}", p1.name()); // name: method: "Boii"
println!("age: {:?}", p1.age()); // age: age: 18
println!("name: {:?}", p1.name); // name: "Boii"
println!("age: {:?}", p1.age); // age: 18
}
|
关联函数
关联函数类似类方法,第一个参数不是 self
,调用的时候使用 ::
符号。
| struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: &str, age: u32) -> Person {
Person {
name: String::from(name),
age,
}
}
}
fn main() {
let p1 = Person::new("John", 19);
}
|