下面这段代码, 会报错,但是错的原因我不太能完全确认,是不是 drop check 原因导致的?
我的理解是:因为 Arg 只是满足 FromInput
的未知类型,所以可能会有手工drop实现? 不确定我理解的对不对,求指导~
use std::marker::PhantomData;
// 通过类型可以从 input 获取具体值
trait FromInput<'a> {
fn from_input(input: &'a String) -> Self;
}
trait Handler {
fn call(&self, input: String) -> String;
}
struct MyHandler<Args, F> {
f: F,
_phantom: PhantomData<Args>,
}
impl<'a, Args, F> Handler for MyHandler<Args, F>
where
Args: FromInput<'a>,
F: Fn(Args) -> String,
{
fn call(&self, input: String) -> String {
let args = Args::from_input(&input);
(self.f)(args)
}
}
报错信息:
error[E0597]: `input` does not live long enough
--> src/lib.rs:23:37
|
17 | impl<'a, Args, F> Handler for MyHandler<Args, F>
| -- lifetime `'a` defined here
...
23 | let args = Args::from_input(&input);
| -----------------^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `input` is borrowed for `'a`
24 | (self.f)(args)
25 | }
| - `input` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=02dcb77ae6bfa008889ac70b07b5fcf5
1
共 5 条评论, 1 页
评论区
写评论谢谢 👍🏻
--
👇
苦瓜小仔: > 如你上面所说的要点,像这类知识,可以在哪里成体系获取?
要点是我自己思考总结的。而且仅仅是(与这里的问题相关的)要点总结,不是系统的总结(意味着有很多细节或者例外)。
最主要的还是多看多思考和观察,从小案例开始理解,变成自己的想法。否则生命周期在你眼里只是一些标记/符号/形式上的东西(以及最基本的省略规则),无法联想,也想不出各种案例。
如果你不从小的难点逐一击破,面对更复杂的东西,你都不知道如何拆解成熟悉的东西。大道至简:)
Rust 官方用户论坛 https://users.rust-lang.org/ 有很多帖子值得阅读,看别人的交流会启发自己。
我可以推荐 @danielhenrymantilla,他的 Github 主页列出的库大都与非常 niche/高深的 生命周期有关(同时他也是一个写宏的专家) —— 虽然我还没有仔细去研究过那些技巧。他正在写一本生命周期的书
书籍:Rust lifetimes: from 'static to ecstatic
仓库:https://github.com/danielhenrymantilla/lifetimes.rs
要点是我自己思考总结的。而且仅仅是(与这里的问题相关的)要点总结,不是系统的总结(意味着有很多细节或者例外)。
最主要的还是多看多思考和观察,从小案例开始理解,变成自己的想法。否则生命周期在你眼里只是一些标记/符号/形式上的东西(以及最基本的省略规则),无法联想,也想不出各种案例。
如果你不从小的难点逐一击破,面对更复杂的东西,你都不知道如何拆解成熟悉的东西。大道至简:)
Rust 官方用户论坛 https://users.rust-lang.org/ 有很多帖子值得阅读,看别人的交流会启发自己。
我可以推荐 @danielhenrymantilla,他的 Github 主页列出的库大都与非常 niche/高深的 生命周期有关(同时他也是一个写宏的专家) —— 虽然我还没有仔细去研究过那些技巧。他正在写一本生命周期的书
书籍:Rust lifetimes: from 'static to ecstatic
仓库:https://github.com/danielhenrymantilla/lifetimes.rs
感谢苦瓜
这个要点特别重要,也增加我对 函数/impl 上生命周期标注的认识。
同时也想请教苦瓜,Rust 的 lifetime 虽然有各种资料,但很多都是比较杂没有成体系,这也是我学习 lifetime 基本概念后,想 deepin 的很大苦恼。比如,除了HRTB这个可以找到并学习;但如你上面所说的要点,像这类知识,可以在哪里成体系获取?不知是否相关较有体系一些的资料推荐,多谢~
--
👇
苦瓜小仔: 或许大多数人对发生在函数上的生命周期标注敏感,但其实 impl 上的泛型也会影响实现中的函数/方法的生命周期。
函数上的 HRTB 例子:https://users.rust-lang.org/t/lifetime-for-passing-in-references-to-methods/89703
和现在的这个一样情况的例子:https://users.rust-lang.org/t/lifetime-error/89437
要点是: 标注在函数上的生命周期(包括定义在 impl 上的生命周期),都表示这个生命周期来自函数外部,说明带有这个生命周期的引用必须能活到那么长(即超出函数还能存活)。这对于函数的输入参数,并不奇怪,因为外部引用通常可以存活到超出函数,但来自函数内部的引用,通常无法超出函数存活 —— 当然两种情况都有例外:
前一种情况的例外:常见于外部生命周期赋予了
&mut self
对于
&mut T
,通常你可以将使用它看作一次 consume(reborrow 也适用),所以上面的代码意味着获取Layer<'a>
的生命周期为 'a 的独占引用,并移入 new_item 内,消耗掉它 —— 这个 Layer 活多长,这个独占引用就活多长,换句话说,一旦当你拿到&'a mut self
,你无法获得&'temporary mut self
和&'temporary self
。是的,当你写每次 new_item 消耗的是一个不长于 'a 的临时独占引用。这才是生命周期的正确用法。
后一种情况的例外:常见于 临时引用的静态生命周期提升
具体案例,见最近的这个帖子
现在这个例子
虽然数据 input 来自函数外部,但所有权移入函数内,其任何引用都产生于函数内部,无法存活到函数之外。这就是报错信息告诉你的。(仔细阅读和理解报错!)
或许大多数人对发生在函数上的生命周期标注敏感,但其实 impl 上的泛型也会影响实现中的函数/方法的生命周期。
函数上的 HRTB 例子:https://users.rust-lang.org/t/lifetime-for-passing-in-references-to-methods/89703
和现在的这个一样情况的例子:https://users.rust-lang.org/t/lifetime-error/89437
要点是: 标注在函数上的生命周期(包括定义在 impl 上的生命周期),都表示这个生命周期来自函数外部,说明带有这个生命周期的引用必须能活到那么长(即超出函数还能存活)。这对于函数的输入参数,并不奇怪,因为外部引用通常可以存活到超出函数,但来自函数内部的引用,通常无法超出函数存活 —— 当然两种情况都有例外:
前一种情况的例外:常见于外部生命周期赋予了
&mut self
对于
&mut T
,通常你可以将使用它看作一次 consume(reborrow 也适用),所以上面的代码意味着获取Layer<'a>
的生命周期为 'a 的独占引用,并移入 new_item 内,消耗掉它 —— 这个 Layer 活多长,这个独占引用就活多长,换句话说,一旦当你拿到&'a mut self
,你无法获得&'temporary mut self
和&'temporary self
。是的,当你写每次 new_item 消耗的是一个不长于 'a 的临时独占引用。这才是生命周期的正确用法。
后一种情况的例外:常见于 临时引用的静态生命周期提升
具体案例,见最近的这个帖子
现在这个例子
虽然数据 input 来自函数外部,但所有权移入函数内,其任何引用都产生于函数内部,无法存活到函数之外。这就是报错信息告诉你的。(仔细阅读和理解报错!)
并不是,而是你需要 HRTB。
playground