Skip to main content

Command Palette

Search for a command to run...

遇到的 Rust 所有权转移问题

Updated
1 min read
遇到的 Rust 所有权转移问题
let client = reqwest::Client::new();
let res = client
    .get(url)
    .send()
    .await;

match res {
    Ok(v) => {
        let text = v.text().await.unwrap();
        let headers = v.headers().clone();
        println!("{}", text.clone());
        HttpResponse::Ok().content_type(headers.get("content-type").unwrap().to_str().unwrap()).body(text)
    },
    Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
}

这里的 v.headers 会报错,说 v 在之前所有权就被转移了,遇到这种问题需要分析。

分析签名

首先看两个函数的签名:

text参数是一个值,返回的是 Result<String>,所以这里的 self转移,转移到 text 函数内部,之后在 text 执行完成时被 drop 掉,结合例子一句话就是 v 在调用 text 后会被消耗。

headers 的参数是一个引用,这里就会涉及到生命周期,签名写完整是这样的:

pub fn headers<'a>(&'a self) -> &'a HeaderMap

这意味着,返回值 &Header 的生命周期不得长于参数 &self,换句话说就是,&Header 要在 &self 之前被回收。

总结

分析完签名后可以发现,例子中的使用顺序是有问题的,headers 应该放在前面,因为他是对 v 实例的借用,借用完会还;而 textinto 一样是转移,用完不会还,v 实例就被回收了。

这里还需要考虑的是,“借用什么时候结束?”,因为当所有的引用都消亡后,才算是归还,才能对 self 本身进行转移。

解法

所以解法有两种:

  1. 第一种简单的调换顺序,然后分别处理 headerstext 的结果:

     let headers = v.headers();
     //....把 headers 处理完
     let text = v.text().await.unwrap();
     //....接着再处理 text
    

    这样这样 headers 处理完后,自身和 v引用都能安全被回收,从而能将所有权转移text 上。

  2. 第二种也要调换顺序,但会做一个拷贝:

     // headers() 返回类型 HeaderMap 实现了 Clone
     let headers = v.headers().clone();
     let text = v.text().await.unwrap();
     //一起处理,因为 clone 解耦了 headers 与 v 的生命周期约束
    

    为了一起处理数据,在拿到 headers 后,对他做一份拷贝,这样后续的操作就和原 headers 引用和 v 的引用无关了,他们两个正常回收,后续使用的是拷贝的新数据。

    这样的性能略低于第一种,因为要做内存拷贝,但影响不微乎其微。

More from this blog

12 月装机行动记录

(Banner 图文无关) 这几天买了新的装备回来升级配置,除了显卡和散热器,其他都更新了,这两个不更新的原因是太贵了。 由于我不太懂选配置,所以还是让朋友给推荐,我说我的预算在 5000 左右,他就给我转了一个整机,配置大概是这样的: CPU:AMD 9700X 主板:微星 B650M GAMING PLUS WIFI 或者 微星 B650M GAMING WIFI 显卡:木有 内存:英睿达/宇瞻 DDR5 6000 32G 硬盘:1T NVMe PCIe4 SSD 读速 3500M...

Dec 7, 20241 min read
12 月装机行动记录

Homekit + cozylife 插座连接 HA

近期在淘宝上买了个 Homekit + cozylife 的插座,就这种: 一开始只通过 iOS 访问,就是只连接 Homekit,长按开关重置插座,iOS 一扫码就连上了,后来我嫌在外面访问不了,又不想掏钱买苹果的 HomePod,于是就装上了 Home Assistant,打算让设备们都连上 HA,这样就不用交苹果税了。 连接方式还是通过 Homekit,一般来说支持 Homekit 设备都能这样连接,先连上 iOS,然后在 Home App 中移除设备,这时候就能在 HA 中找到设备了:...

Nov 30, 20241 min read
Homekit + cozylife 插座连接 HA

找到了一台祖传的 Ccd 相机

开个玩笑,这台相机其实是我们家在 05 年的时候买的,发票都还在呢,当时花了 4000 块钱!搁现在我都受不了,更别说当年了,看到价格我都震惊了。 相机的型号是索尼的 Cybershot DSC-N1,属于小红书时尚单品 CCD 相机,由于一直放在包装盒里,现在还有 99 新呢。 机子还是正常的,能开机,能拍照,其中一个问题是日期,这款没有 WiFi 功能,所以时间只能保存在本地,不知道是不是 BUG,每次开机都让我重新设置,默认就定在 2005 年 1 月 1 日。 第二个问题是电池,电池应该...

Nov 28, 20241 min read
找到了一台祖传的 Ccd 相机

记录和 ffmpeg 与 LLM 搏斗的两天

要做的 最近在写一个制作视频的功能,就是把 N 个视频合并,然后把对应的 N 张图片,在视频开始的前 5 秒叠加显示出来。 第一口 - diffusion studio 本来我用的是 diffusion studio,这是一个 JS 库,但这玩意性能太差了,因为他要把视频每一帧都读到 canvas 里,数据一多页面就卡住了(为啥要折腾 DOM 呢?) 而且他的 API 十分不好用,作为浏览器脚本你无法读本地数据也就算了,你起码给一个接受纯数据的参数吧,比如 HTML 类型接受源代码,Image ...

Nov 16, 20242 min read
记录和 ffmpeg 与 LLM 搏斗的两天
V

void mian

39 posts