< 返回版块
NenX 发表于 2025-05-28 17:36
Tags:小弟在学习 Rust 生命周期的时候遇到问题,恳请各路高手相助!为什么下面的代码可以编译通过?在 test_call 中 ff 的类型是 Fn(&'static str) 吗?为什么 Fn(&'static str) 可以接受 &'out str 作为参数 ?为什么 ff1 可以不能接受 &'out str 作为参数
fn main() {
let s = "out".to_string();
test_call(s.as_str());
}
fn test_call<'out>(t_str: &'out str) {
// ff 的类型是 Fn(&'static str) 吗?
let ff = make_closure("inner");
// 为什么 Fn(&'static str) 可以接受 &'out str 作为参数 ???
ff(t_str);
let ff1:&dyn Fn(&'static str) = &make_closure("inner");
// ff1 不能接受 &'out str 作为参数 ???
// ff1(t_str); // 这里出错了
}
fn make_closure<'x>(a: &'x str) -> impl Fn(&'x str) {
return move |instr: &'x str| println!("{a} {instr}");
}
1
共 8 条评论, 1 页
评论区
写评论谢谢各位大佬!!
针对这段代码我做一个简要总结:'out 的生命周期短于 'static,rust生命周期原则短的不能赋给长的
代码解读我就不写了,只回答你的几个问题:
不是的,返回位置的
impl
(RPIT)默认捕获全部的生命周期(可以了解一下最近的use<'_>
语法,但与本题无关),所以ff
的类型是Fn(&'x str) + 'x
,由于'x
实体类型没有指定,所以会根据上下文自动推导Fn(&'static str)
不可以接受&'out str
的参数,除非明确限定了生命周期边界'out: 'static
,否则就违反了生命周期规则(实参存活不够久,形参要求更久)同2。因为
ff1
被明确限定为Fn(&'static str)
,所以不能接受比'static
活的短的参数另外考虑你可能有疑惑的几个点
对于
make_closure<'x>
方法,因为协变关系,生命周期满足'static: 'x
(但并不表示'x = 'static
),所以返回的闭包的生命周期依然是'x
,且与make_closure
的参数只有间接的边界限定关系,在调用ff
的时候传入'out
的类型,所以'x
会被推导为'out
,并不破坏生命周期规则。对于
ff1
因为你主动限定了类型,所以'x
自然会推导为'static
,所以上面问题2和3的回答,应该不需要赘述了我凭经验分析的, 可能有误 首先
'out
和'x
都是正常的生命周期标记, 唯独'static
, 我们都知道 static 的生命周期是和软件的生命周期相同, 软件不关闭, static就一直存在. 那解释的通了, static生命周期就天然大于其他生命周期, 因为static是一直存在的不可能有其他的生命周期比他大. 回到代码解读, 在第一个 ff 这里并不是static生命周期, 还是x生命周期, out和x同大, 所以out可以正常传入, 但是 ff1 显性的标记了static, 由于static 的生命周期大于x, 规则成立, 所以static可以传入x, 但是当再传入out时, out的生命周期是没有static大的, 所以报错了, ff1只能传入static生命周期的参数.通过vscode插件的类型推理也能证明这一点
生命周期标注在这段代码里没有什么用, 把所有的标注都删了都没问题
不过我猜你的疑问应该是为什么传入的 "inner" 字符串常量返回的闭包并不是'static的, 我理解的是生命周期标注并不是一个参数, 他要在使用的时候进行分析, 比如字符串常量它的生命周期就是最大的, 没有比他更大的生命周期, 在使用时它不可能被释放或是不存在, 所以在使用时可以不考虑静态生命周期, 去除静态生命周期后就可把两个函数和闭包看作同一个生命周期, 所以去除生命周期标注也不会报错, 不过想要体验生命周期长短的代码我在你的代码基础上改出来, 把静态生命周期引用移除函数, 这样就有了两个不同生命周期的引用参数, 传入函数时就必须要对比两个生命周期的大小
rustc: 1.87.0
报错信息你是一点不看啊
lifetime may not live long enough type annotation requires that
'out
must outlive'static
你想保持住那个'static,可以这么改,会影响到调用方,但是是必须的,符合rust生命周期的逻辑
不懂,给闭包加个标记,然后交给推断了。
我有点疑惑,ff 的类型是 Fn(&'static str) 吗?
--
👇
bestgopher: 涉及到协变,逆变了吧
涉及到协变,逆变了吧