在match语句中将Option<String>转换为Option<&str>的问题
我明白你现在遇到的困扰了:你把文件读取返回的Result<String>转成了Option<String>,但目标函数需要的是Option<&str>,尝试在match里返回Some(&s)的时候编译器直接报错了,对吧?
咱们先搞清楚为什么会报错:你之前的写法是在match的Ok分支里把String移动到了局部变量s里,然后取它的引用&s。但这个局部变量s只会在这个match分支里存在,分支结束后s就会被销毁,那返回的引用就变成了“悬空引用”——指向已经被释放的内存,Rust的借用检查器绝对不允许这种情况发生,所以编译器直接给你亮红灯了。
下面给你两个靠谱的解决方案:
方案1:用标准库的as_deref()方法(推荐)
Rust标准库早就为这种场景准备了现成的方法,as_deref()可以直接把Option<String>转换成Option<&str>,而且能完美处理生命周期问题,写法还特别简洁:
// 先把Result直接转成Option,比手动写match更简洁 let geom_source_opt: Option<String> = std::fs::read_to_string(folder.join("shader.geom")).ok(); // 用as_deref()转成Option<&str> let geom_source_ref: Option<&str> = geom_source_opt.as_deref();
as_deref()的作用就是把持有所有权的Option类型,转换成对应引用类型的Option,对于String来说就是转成&str,而且它会保证引用的生命周期和原来的Option<String>绑定,只要geom_source_opt还没被销毁,geom_source_ref就有效。
方案2:在match分支里用ref关键字获取引用
如果你更习惯用match手动处理,那可以在Ok分支里用ref关键字,这样我们拿到的是对原Result中String的引用,而不是把它移动到局部变量里:
let geom_source_result = std::fs::read_to_string(folder.join("shader.geom")); let geom_source_ref: Option<&str> = match geom_source_result { // 用ref s获取对Ok中String的引用,而不是移动它 Ok(ref s) => Some(s), Err(_) => None, };
这里要注意:不能提前销毁geom_source_result,比如不能在geom_source_ref还在使用的时候就把geom_source_resultdrop掉,否则引用就会悬空,编译器同样会报错。
另外补充一句,其实你一开始手动写match把Result转成Option的步骤,可以用Result::ok()方法代替,和你写的match逻辑完全一样,但代码更短,就像方案1里那样。
内容来源于stack exchange

