Rust 从结构体中取字段的引用

场景一:拥有结构体变量 t: T,想获取 T 的两个字段的引用

代码:

rust 复制代码
struct Foo {
    pub a: i32,
    pub b: u32,
}
fn main() {
    let foo = Foo { a: 1, b: 2 };
    let a_p = &foo.a;
    let b_p = &foo.b;
    println!("a: {}, b: {}", a_p, b_p);
}

可以直接使用 &foo.a 的语法获取结构体中字段的引用。

场景二:拥有结构体变量 t: T,想获取 T 的两个字段的可变引用

代码:

rust 复制代码
struct Foo {
    pub a: i32,
    pub b: u32,
}
fn main() {
    let mut foo = Foo { a: 1, b: 2 };
    {
        let a_mut = &mut foo.a;
        let b_mut = &mut foo.b;
        *a_mut += 1;
        *b_mut += 1;
    }
    let p = &foo;
    println!("a: {}, b: {}", p.a, p.b);
}

可以使用 &mut foo.a 的语法获取结构体中字段的可变引用,而且还可以同时获得同一结构体变量的另一个字段的可变引用(不违反对同一变量的可变引用不能同时存在)。

在持有可变引用时,想修改变量需使用 *p = 的语法

场景三:拥有变量 t: T 的不可变引用,想获取 T 的两个字段的引用

代码:

rust 复制代码
struct Foo {
    pub a: i32,
    pub b: u32,
}
fn main() {
    let foo = Foo { a: 1, b: 2 };
    let p = &foo;
    let a = p.a; // 等价于 let a = (*p).a; 编译器会自动解引用
    let b = &p.b;
    println!("a: {}, b: {}", a, b);
}

引用使用起来就像直接持有了变量。

场景四:拥有 Guard 变量 p: guard<T>,想获取 T 的两个字段的可变引用

代码(错误示范):

rust 复制代码
use spin::Mutex;

struct Foo {
    pub a: i32,
    pub b: u32,
}
fn main() {
    let foo = Mutex::new(Foo { a: 1, b: 2 });
    {
        let mut foo: spin::MutexGuard<'_, Foo> = foo.lock();
        let a_mut = &mut foo.a;
        let b_mut = &mut foo.b;
        *a_mut += 1;
        *b_mut += 1;
    }
    let p = foo.lock();
    println!("a: {}, b: {}", p.a, p.b);
}

/// 编译结果
error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> src/main.rs:12:26
   |
11 |         let a_mut = &mut foo.a;
   |                          --- first mutable borrow occurs here
12 |         let b_mut = &mut foo.b;
   |                          ^^^ second mutable borrow occurs here
13 |         *a_mut += 1;
   |         ----------- first borrow later used here

For more information about this error, try `rustc --explain E0499`.

此时不能使用与场景二同样的代码。虽然 foo: MutexGuard 实现了 Deref trait 以便被当作普通引用使用(当执行 foo.a 时,实际上发生的是 (*foo.deref()).a,或者考虑到可变性,发生的是 (*foo.deref_mut()).a 以先获取 mut Foo)。在加入了 deref() 的一步后,编译器就无法判定你最终获取的两个可变引用是否重叠了。

相关推荐
爱吃香菜的初学者5 分钟前
十六.Linux——多线程(2)
linux·运维·开发语言
jeo陽19 分钟前
04-循环实战:素数、最大公约数、级数求和与枚举法
c语言·开发语言·数据结构
暖核38 分钟前
kubeadm 集群运维:Worker 节点下线删除、整套集群销毁重建指南
运维·开发语言·php
tachibana21 小时前
Go 语言里的 Context 是什么?
开发语言·后端·golang·go·语言
天桥下的卖艺者1 小时前
R语言使用ggcube包轻松绘制文章中的各类3D图形
开发语言·3d·r语言
唐钰小宝B2 小时前
深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
java·开发语言·windows
知识分享小能手3 小时前
C学习教程,从入门到精通,C语言指针 —— 详细知识点总结(10)
c语言·开发语言·学习
熊猫钓鱼>_>3 小时前
开源鸿蒙平台 KMP 三方库 kotlin-csv 适配全流程:从编码假设到沙箱真机互通验证
开发语言·人工智能·华为·kotlin·harmonyos·鸿蒙
张张123y3 小时前
# 后端第七课:FastAPI 实战入门(用刚学的 Python 写第一个 API 接口)
开发语言·python·mysql·api·fastapi
小陈不好吃4 小时前
Java 泛型与类型擦除:从 PECS 原则到 TypeToken 绕过
java·开发语言·windows·pecs 原则·typetoken绕过