命名结构体 有些也称作为具名结构体,就是指每个字段都有名字的结构体,它的每个字段都有明确的名字和类型。 #[derive(Debug)]
struct Person {
name: String,
age: u32,
role: String,
}
struct _Society {
year: u32,
persons: Vec<Person>, // struct可作为另一个struct的变量类型
}
fn main() {
let farmer = Person {
name: String::from("ohBug"),
age: 18,
role: String::from("Farmer"),
};
let name = String::from("Qidai");
let age = 22;
let mut busi_man = Person {
name,
age,
role: String::from("busi_man"),
};
println!("busi_man = {:?}", busi_man);
println!("Farmer = {:?}", farmer);
// 更新字段,注意busi_man是mut修饰
busi_man.name = String::from("beggar");
println!("busi_man = {:?}", busi_man);
let busi_man_name = busi_man.name;
println!("busi_man_name = {}", busi_man_name);
// error 因为name字段是String类型,所以有所有权概念,现在所有权已经归属于 busi_man_name,所以不能整体打印 busi_man
// println!("busi_man = {:?}", busi_man);
// 但是可以打印没有被影响的字段
println!("busi_man = {:?}", busi_man.role);
let farmer_two = Person {
name: String::from("twoxx"),
age: 45,
..farmer // farmer的role并不会变,可使用此种赋值方式。
};
println!("farmer_two = {:?}", farmer_two)
}
// output
busi_man = Person { name: "Qidai", age: 22, role: "busi_man" }
Farmer = Person { name: "ohBug", age: 18, role: "Farmer" }
busi_man = Person { name: "beggar", age: 22, role: "busi_man" }
busi_man_name = beggar
busi_man = "busi_man"
farmer_two = Person { name: "twoxx", age: 45, role: "Farmer" }
匿名结构体 #[derive(Debug)]
struct point_2d {
x: i32,
y: i32,
}
#[derive(Debug)]
struct circle_2d {
point: point_2d,
radius: i32,
}
// 元组结构体,对于一些结构描述的更加清晰直接
#[derive(Debug)]
struct circle((i32, i32), i32);
fn main() {
let point = point_2d { x: 31, y: 42 };
let _circle = circle_2d { point, radius: 12 };
println!("{:?}", _circle);
// 元组结构体
let tuple_circle = circle((31, 42), 12);
println!("{:?}", tuple_circle);
}
// output
circle_2d { point: point_2d { x: 31, y: 42 }, radius: 12 }
circle((31, 42), 12)
单元结构体 #[derive(Debug)]
struct FLAG;
fn main() {
let flag = FLAG;
println!("{:?}", flag)
}
//ouput
FLAG
面向对象 构造方法 // Default 默认构造器,就是将Person初始化的时候,对象中的各个字段都是默认值
#[derive(Debug, Default)]
struct Person {
name: String,
age: u32,
}
impl Person {
// 构造,new只是方法名,并非强制
fn new(name: &str, age: u32) -> Person{
Person {
name: name.to_string(), age,
}
}
}
fn main() {
let person = Person::new("ohBug", 20);
println!("{:?}", person);
let default_person = Person::default();
// 与上面作用一样
// let default_person: Person = Default::default();
println!("{:?}", default_person);
}
//output
Person { name: "ohBug", age: 20 }
Person { name: "", age: 0 }
实例方法&静态方法 #[derive(Debug)]
struct Person {
name: String,
age: u32,
}
// 实例方法
impl Person {
// 如果不是&Self引用类型,则在对象调用此方法后,则对象已经被销毁,因为所有权机制,如果相对其修改则是&mut self
fn say_my_name(self: &Self) {
println!("name = {}", self.name)
}
// 此参数是上面的语法糖
fn say_my_age(&self) {
println!("age = {}", self.age)
}
}
// 实例方法, 可以多次impl一个struct来实现多个方法
impl Person {
fn la_bb(&self, msg: &str) -> &str {
print!("{msg} ~");
for _ in 0..self.age {
print!("💩")
}
return " shuang";
}
}
// 关联方法 (静态方法)
impl Person {
fn cal(x: u32, y: u32) -> u32{
x + y
}
}
fn main() {
let person = Person {
name: String::from("ohBug"),
age: 20
};
person.say_my_age();
person.say_my_name();
let msg = person.la_bb("start ...");
println!("{msg}");
// 静态方法则用结构体名调用,与Java不同,Rust中person对象并不能调用cal,只能struct
// let result = person::cal(2, 3);
let result = Person::cal(1, 2);
println!("{result}")
}
// output
age = 20
name = ohBug
start ... ~💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩 shuang
3
枚举 枚举中的单个枚举被称为枚举类型的变体,不能对具体的单个变体进行impl
操作。 #[derive(Debug)]
struct Person {
name: String,
age: u32,
}
// 枚举可以包罗万象
#[derive(Debug)]
enum EveryThing {
Person,
Circle((i32, i32), i32),
Open(bool),
NoName,
Dog {
color: (i32, i32, i32),
name: String,
age: DogAge,
},
}
#[derive(Debug)]
enum DogAge {
OneYears = 1, // 给一个初始值1,后面依次递增
TwoYears,
ThreeYears,
}
impl EveryThing {
// 实例方法 match可有返回值也可没有,如下是对枚举进行解构
fn say(&self, msg: String) -> String {
let type_msg = match self {
Self::Person => "Person",
Self::Circle((x, y), radius) => &format!("Circle radius = {radius}"),
Self::Open(flag) => &format!("Open flag = {flag}"),
Self::Dog { color, name, age } => &format!("Dog name = {name}"),
_ => "others", // 匹配不到上面的默认处理
};
format!("{type_msg} {msg}")
}
}
impl EveryThing {
// 静态方法
fn view(target: &EveryThing) {
println!("{:?}", target)
}
}
fn main() {
let person = Person {
name: "ohBug".to_string(),
age: 20,
};
println!("person = {:?}", person);
let person_everything = EveryThing::Person;
println!("person_everyThing = {:?}", person_everything);
let circle_everything = EveryThing::Circle((23, 12), 5);
println!("circle_everything = {:?}", circle_everything);
let dog_age = DogAge::ThreeYears;
println!("dog_age = {:?}", dog_age);
println!("dog_age = {:?}", dog_age as i32);
let dog: EveryThing = EveryThing::Dog {
color: (1, 2, 3),
name: ("Berber".to_string()),
age: DogAge::TwoYears,
};
println!("dog = {:?}", dog);
let dog_msg = dog.say("wangwang".to_string());
println!("dog_msg = {dog_msg}");
EveryThing::view(&dog);
// :_ 指定方式可以忽略掉编译器的未使用的警告, 且后续不能够使用此变量
// 在解构的时候是可以进行重新命名的
let EveryThing::Dog {color, name: _, age: aaa} = dog else {
panic!("not a dog");
};
println!("color = {:?}", color);
// 后续不能够使用此变量
// println!("name = {name}");
println!("age = {:?}", aaa);
}
// output
person = Person { name: "ohBug", age: 20 }
person_everyThing = Person
circle_everything = Circle((23, 12), 5)
dog_age = ThreeYears
dog_age = 3
dog = Dog { color: (1, 2, 3), name: "Berber", age: TwoYears }
dog_msg = Dog name = Berber wangwang
Dog { color: (1, 2, 3), name: "Berber", age: TwoYears }
color = (1, 2, 3)
age = TwoYears
模式匹配 上面已经写了一些对枚举类型的对象进行解构。除了match可以进行解构外,还可以使用let。 #[derive(Debug)]
struct Person {
name: String,
age: u32,
}
fn main() {
let person = Person {
name: "ohBug".to_string(),
age: 20,
};
if let Person {name, age} = person {
println!("is a person {name}");
}else {
println!("not a person");
}
}
//output
is a person ohBug
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
fn main() {
let person = Person {
name: "ohBug".to_string(),
age: 20,
};
// ref 是在模式匹配过程中提供⼀个额外的信息,告诉编译器只是需要读取⼀下字段的值⽽已,
// 不需要获得它的所有权,ref带来的改变就是获取&person.name
// 还有一个 ref mut 的形式,表示name可变,即可变引用。
if let Person {ref name, age} = person {
println!("is a person {name}");
}else {
println!("not a person");
}
// 如果没有ref,则这里报错
let person_name = person.name;
println!("{person_name}")
}
思考 因为基础类型以及切片类型都是不具有所有权的类型, Rust 默认不会深度拷⻉数据,如果最后let c: String = *b;
成立,则意味着要夺⾛a的所有权。为了不被夺走所有权,则Rust直接阻止了这种方式,也给出了提示,除非所有权类型实现了`Copy` trait
。 fn main() {
let a: i32 = 3;
let b: &i32 = &a;
let c: i32 = *b;
println!("{c}");
let a: &str = "3";
let b: &&str = &a;
let c: &str = *b;
println!("{c}");
let a: String = "3".to_string();
let b: &String = &a;
let c: String = *b;
// error: ^^ move occurs because `*b` has type `String`
// , which does not implement the `Copy` trait
println!("{c}");
}
如下,由上面经验告诉我们解引用会带来所有权的转移,但是在枚举上self
和*self
效果是一样的,且所有权并不会受到影响,这是因为在枚举match
时只是对类型进行了匹配,并不会进行对负载的匹配捕获,因此不存在赋值操作,所以也就没有了所有权问题。进而跟copy trait
也就没关系了。其match
效果一样是Rust进行了自动的解引用操作。 enum Animal {
Cat,Dog
}
impl Animal {
fn is(&self) {
match self {
Self::Cat => print!("cat"),
Self::Dog => print!("dog"),
}
}
fn isa(&self) {
match *self {
Self::Cat => print!("cat"),
Self::Dog => print!("dog"),
}
}
}
fn main() {
let dog = Animal::Dog;
dog.is();
dog.isa();
dog.is();
}
// output
dogdogdog