Rust的自定义类型

Rust中的自定义类型

希望能帮助你对Rust的自定义类型变量有更好的认识和理解,如有错误,恳请斧正。

1.具名结构体

struct Person {
    name: String,
    age: u8,
}

fn describe(person: &Person) {
    println!("{} is {} years old", person.name, person.age);
}

fn main() {
    let mut peter = Person { name: String::from("Peter"), age: 27 };
    describe(&peter);

    peter.age = 28;
    describe(&peter);

    let name = String::from("Avery");
    let age = 39;
    let avery = Person { name, age };
    describe(&avery);

    let jackie = Person { name: String::from("Jackie"), ..avery };
    describe(&jackie);
}

结构体变量的生命周期一定要长于其成员的生命周期,

在声明结构体的时候加上mut关键字,允许我们对结构体内容进行修改

如果在结尾加上这些代码就会出现这样的问题:

    let ownership_move = peter.name;
    describe(&peter)


error[E0382]: borrow of partially moved value: `peter`
  --> src/main.rs:26:14
   |
25 |     let ownership_move = peter.name;
   |                          ---------- value partially moved here
26 |     describe(&peter)
   |              ^^^^^^ value borrowed here after partial move
   |
   = note: partial move occurs because `peter.name` has type `String`, which does not implement the `Copy` trait

在 Rust 中,String 是一个可变字符串,它在赋值给 ownership_move 时会发生所有权转移,意味着 peter.name 已经不再是有效的 String 实例。

因此,在 describe 函数内部尝试访问 &peter.name 时,由于 petername 已经被移动了所有权,所以会导致编译错误。

解决方案很简单,时刻注意不要移动所有权即可

其中..avery(本例的用法,avery是你想要复制的旧结构体)语法允许我们,轻松的copy旧结构体的大部分字段,而无需明确键入所有字段,但它必须始终是最后一个元素!

在使用这个语法的时候要注意字段是否实现了Copytrait,否则可能会发生所有权转移,出现先前我们看到的编译错误。

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

fn describe(person: &Person) {
    println!("{} is {} years old", person.name, person.age);
}

fn main() {
    let mut peter = Person {
        name: String::from("Peter"),
        age: 27,
    };
    describe(&peter);

    peter.age = 28;
    describe(&peter);

    let name = String::from("Avery");
    let age = 39;
    let avery = Person { name, age };
    describe(&avery);

    let demo_1 = Person {
        name: String::from("demo1"),
        ..avery
    };
    println!("{:#?}",demo_1);
    println!("{:#?}",avery);
    let demo_2 = Person{
        age:5,
        ..avery
    };
    println!("{:#?}",demo_2);
    // 加入这一行代码会出现错误:error[E0382]: borrow of partially moved value: `avery`
    // println!("{:#?}",avery);
}

2.元组结构体

某些情况下字段的名字并不重要,可以使用元组结构体。

#[derive(Debug)]
struct demo(i32, i32);

#[derive(Debug)]
struct demo_1(String, i32);
fn main() {
    let p = demo(10, 6);
    println!("{p:#?}");

    let p = demo_1(String::from("demo_1"), 3);
    println!("{p:#?}");
    println!("{}  {}", p.0, p.1);
    let demo_1(x, y) = p;
    println!("{} {}",x,y)
}

元组结构体的常见用法

  1. 简单的数据封装:可以组合几个相关的值,并且他们之间的关系相对简单,不需要给每个字段赋予特定的含义时。

    struct Rgb(u8,u8,u8);
    // let red = Color(255,0,0);  
    // 上面这段代码表示颜色红色
    
  2. 命名元组:元组结构体提供了比普通元组更好的可读性,他为整个组合赋予了明确的意义,即使各个字段没有名字

  3. 泛型约束和类型系统

  4. 协议和数据交换

3.枚举

Rust中的枚举是一种强大的类型,它可以让你定义一个类型,该类型能够取有限的一系列离散的值。

枚举中的每一个变体(Variant)都代表一种可能的状态或值。变体是可以是空的(unit-like),也可以携带数据

#[derive(Debug)]
enum Direction {
    Left,
    Right,
}

#[derive(Debug)]
enum PlayerMove {
    // 不携带数据,仅作为标记
    Pass,                        // Simple variant
    // 携带一组匿名数据,就像元组一样
    Run(Direction),              // Tuple variant
    // 携带命名字段的数据,就像结构体一样
    Teleport { x: u32, y: u32 }, // Struct variant
}

fn main() {
    let m: PlayerMove = PlayerMove::Run(Direction::Left);
    println!("On this turn: {:?}", m);
    
    // 通过模式匹配提取枚举中的值
    let pattern_demo = PlayerMove::Teleport {x:10,y:6};
    if let PlayerMove::Teleport { x, y } = pattern_demo{
        println!("x is {},y is {}",x,y);
    }
}

在内存中PlauerMove的实例将会分为两部分存储:

  1. Discriminant(标签):存储一个整数值,代表当前实例是属于PlayerMove枚举中的哪一个变体。这个整数值具体大小取决于枚举中变体的数量和编译器的优化策略。Rust 编译器会自动为每个变体分配一个唯一的标签值,从 0 开始依次排列(如果没有手动指定)。
  2. Payload(负载数据):根据变体的定义,存储相应的负载数据。
  • 每当创建一个PlayerMove实例,Rust首先在内存中放置标签,接着紧跟负载数据(如果有的话)。
  • 在访问PlayerMove的值时,可以通过模式匹配等方式来解析出具体的变体及其携带的数据。
  • 可以利用repr来控制discriminant,但正常情况下,通常无需关注枚举的底层标签值,以免引起一些莫名其妙的错误。
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值