1 Struct
结构体实例化的顺序可以不与定义时候一样,但是所有属性都得实例化。结构体实例声明为可变的时候其所有属性都是可变的。
基本的结构体
声明一个结构体
struct User{
name : String,
email : String,
sign_in_count : u64,
archive : bool,
}
fn main(){
let mut user = User{
email : String::from("ycc@123.com"),
name : String::from("ycc"),
sign_in_count : 1,
archive : false,
};
println!("{}",user.email);
}
struct作为函数的返回值:
fn fun()-> User{
User{
email : String::from("ycc@123.com"),
name : String::from("ycc"),
sign_in_count : 1,
archive : false,
};
}
字段初始化简写的方式,省略赋值的操作
fn build_user(name:String,email:String) ->User{
User{
// email : email,
// name : name,
email,
name,
sign_in_count : 1,
archive : false,
};
}
当想基于一个struct来创建一个新的struct的时候,可以使用下面的语法糖:
fn main(){
let user1 = User{
email : String::from("ycc@123.com"),
name : String::from("ycc"),
sign_in_count : 1,
archive : false,
};
let user2 = User{
email : String::from("233@gmail.com"),
..user1
};
}
Tuple Struct
元组结构体,适用于给tuple分类型,让这个元组不同于其他的元组,比如可以声明一个元组结构体来描述,颜色RGB,正方形,圆。。。等等
先复习下元组:元组内可以放入不同类型的值
fn main(){
let trple = (1,"a",3); // 元组
let (a,b,c) = trple; // 解构
println!("{}",a)
}
元组结构体:
fn main(){
// 元组结构体
let white = Color(0,0,0);
let orange = Color(2,5,1);
}
struct Color(i32,i32,i32);
没有任何字段的Struct
可以定义一个没有任何内容的struct,叫做 Unit-like struct,可以实现抽象的描述,但是又不需要存储元素内容的场景可以适用。
struct的所有权
Struct里面可以放数据,也可以放引用(生命周期),生命周期保证只要struct实例是有效的,那么里面的引用就是有效的,如果使用引用却不使用生命周期就会报错
小例子
实现计算矩形的面积:
struct Rectangle {
length: u32,
width: u32,
}
fn get_area(r : &Rectangle) -> u32 {
r.length * r.width
}
fn main() {
let r = Rectangle{
length:10,
width:10,
};
let area = get_area(&r);
println!("{}",area);
}
注意这里传入的是结构体的引用,因此,在 方法执行结束,main方法依然有 Rectangle的实例r的所有权,因此还可以打印:
println!("{}",r)
但如果直接这么打印编译会报错:提示没有实现这个接口,或则使用第二种方法
= help: the trait
std::fmt::Displayis not implemented forRectangle= note: in format strings you may be able to use{:?}(or {:#?} for pretty-print) instead
而当你使用第二种方式打印的话还会报错:
println!("{:?}",r)
println!("{:#?}",r) //美化打印
提示你没有时间Debug接口,或者使用这个注解,放在结构体上面,
= help: the trait
Debugis not implemented forRectangle= note: add#[derive(Debug)]toRectangleor manuallyimpl Debug for Rectangle
方法
方法表示与这个结构体有关的函数,使用关键字 impl来表示,可以有很多个代码快,除了特别的方法,一般的方法第一个参数总是自己,用 &self表示,方法调用可以省略自身的引用入参
- self 可以是 借用:
&self,也可以是:safe表示获取所有权,也可以是可变的,也就是说和普通的参数没啥区别
impl Rectangle {
fn get_area(&self) -> u32 {
self.length * self.width
}
}
fn main() {
let r = Rectangle{
length:10,
width:10,
};
let area = r.get_area();
println!("{}",area);
}
方法调用的运算符
在c/c++中方法调用,是这样的:object->someting() 和 (*object).someting()这两者等价
- object是个指针,星号表示解指针,变为对象
- Rust提供了自动的引用,或者解引用,在调用方法的时候,rust会自动的补上,&,& mut 等,来匹配上方法的入参
关联函数:
impl Rectangle {
fn square(size:u32) -> Rectangle {
Rectangle{
length :size,
width :size,
}
}
}
fn main() {
// 关联函数的调用
let squ = Rectangle::square(10);
println!("{:#?}",squ)
}
2 枚举
定义一个枚举,不过看了半天,没有发现和java类似的那种常量形式的枚举定义方式
enum IP_ADDRESS{
V4(String,u32),
V6,
}
标准库的Option <T>枚举包含在预导入模块中的,可以直接使用,其结构为:
pub enum Option<T> {
None,
Some( T),
}
当想使用包裹着值的,y变量时候,提示需要转换才行,不能直接使用,这样就保证了空安全的情况
fn main() {
let x : i8 = 5;
let y : Option<i8> = Some(5);
//let z = y.expect("i8");
let sum = x + z;
println!("{}",sum);
}
3 模式匹配
模式匹配必须穷举所有的可能,否则编译不予通过
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
附带值的模式匹配:
#[derive(Debug)] // 这样可以立刻看到州的名称
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}
可以使用占位符 -来表示其他情况
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}
针对一种情况,可以使用if letif let,代码更为简洁
fn main(){
let v = Some(1);
match v {
Some(3)=> println!("3"),
_ => (),
}
//针对一种情况,可以使用if let
if let Some(3) = v {
println!("3")
}
}