本文最后更新于 117 天前,其中的信息可能已经有所发展或是发生改变。
原题
实现一个签名函数to_static_str让它的返回值生命周期为 ‘static
fn to_static_str(s:String)->&'static str {
}
fn main {
let s = "xxx";
let s1 = to_static_str(s.clone);
assert(s==s1);
}
分析
首先,看到题目第一眼,我想到了《圣经》中的一段代码示例
fn dangle() -> &String { // dangle 返回一个字符串的引用
let s = String::from("hello"); // s 是一个新字符串
&s // 返回字符串 s 的引用
} // 这里 s 离开作用域并被丢弃。其内存被释放。
// 危险!
这是一段悬垂引用的示例,这里正常返回了借用的s,但是s在函数结束时已经被释放了,如果我们直接返回s,就可以正常返回 然后我们结合题目,如果我们返回s,那他的生命周期为`a,这不符合我们的需求
这里我们剖析一下我们的需求,首先就是我们需要生命周期为`static的返回值,这意味着这个返回值的所有权不能移交给别人,那我们就需要让上文的悬垂引用实现,接下来我们的问题是当我们 &s,它已经被释放了,等等,写到这里,我突然想到了发散函数,如果我们在发散函数中借用了s,是否意味着s的生命周期发生改变?让我们试试
fn forever(s2:String) -> !{
loop {
&s2;
};
}
fn to_static_str(s:String)->&'static str {
forever(s);
&s
}
fn main() {
let s = "xxx";
let s1 = s.clone();
let s2 = to_static_str(s1.to_string());
assert_eq!(s,s1);
}
总结
结果是这个代码报了一堆warning然后应该是编译不出来,我还是再多学学再研究这个吧
@ling 坑爹,超纲了
这段代码当然编译不出来,forever需要的是String类型,它会拿走变量的所有权,forever(s)之后,s已经失效了,你再&s,这不是悬垂引用了?
而且forever不会返回,在forever调用后面的代码根本没有机会执行。
另外,其他模块持有引用,并不会改变引用的生命周期,Rust只会要求你必须保证引用的生命周期足够长,而不会在运行时改变它。