了解生命周期:最大生命周期和“静态”
Understanding lifetimes: max lifetime and 'static
我对 Rust 生命周期的学习过程是这样的(基于 Rust 书):
- 我想注释,当引用后面的值超出范围时
- 通常(不总是!参见 .data 部分,即“静态”)值位于
{}
块中
- 我们注释像
't: {…}
这样的块,例如结构字段的生命周期类似于 &'t ident
,具有相同的生命周期名称 t
- 这个理解是错误的。为什么?结构实现者很可能不知道块名称定义,并且同一结构可能有多个块名称定义。
- 所以定义
't: {…}
和用法&'t ident
必须完全独立
- 编译器可以轻松确定定义,因此用户无需编写
't: {…}
。程序员只需要关心&'t ident
规范部分。
- 编译器可以分析函数体(在
struct
的情况下:使用结构成员)并确定 &'t ident
部分。
- 这个理解是错误的。为什么?因为有时候函数体(或者struct成员的使用)还不可用(比如一个trait指定了一个函数,但是实现是由其他人在未来完成的)。
- 因此,
struct
和 fn
必须分别在其结构定义或函数签名中完全指定生命周期。
- 规范大多遵循相同的启发式规则。所以我们引入了生命周期省略。它根据针对最常见用例的规则插入生命周期,我们可以随时选择退出。
在这一点上,我认为我的理解非常接近它的实际工作原理。但是现在,我的理解出错了。让我们看一些例子:
#[derive(Debug)]
struct Stats {
league: &str,
}
const NAME: &str = "rust";
fn more_difficult_league(s1: &Stats, s2: &Stats) -> &str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let mut st = Stats { league: name };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}
显然,我省略了任何生命周期规格。
结构字段的生命周期要么是程序的整个持续时间('static
),要么与结构(Stats<'a>
和 league: &'a str
)一样长
在 function/method 中,我们可能会得到生命周期为 'a
、'b
、'c
、……的引用。 return 值的生命周期是多少?
- 要么是某个静态值(
'static
)
- 要么总是相同的特定生命周期(如
'c
)
- 它要么是一个特定的生命周期 - 哪个生命周期将在编译时或 运行 时已知。对于编译器,我们必须指定最坏情况下的生命周期
max('a, 'b, 'c, …)
。据我所知,这可以通过为每个参考提供相同的生命周期来完成。
这似乎适用于以下人为设计的较短函数:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'a str {
if s1.league == s2.league {
s1.league
} else {
s2.league
}
}
如果我们添加一些 'static
return 值,最坏情况下的生命周期是 max('a, 'static)
,大概是 'static
:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'static str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
这为 s2.league
提供了 error[E0621]: explicit lifetime required in the type of s1
和 lifetime 'static required
。
我的理解错在哪里?在此先感谢您的耐心等待。
免责声明: help: add explicit lifetime 'static to the type of s1: &'a Stats<'static>
可以在这里工作,但我觉得不对。
我会按照下面提供的方式更改您的代码。
而不是假装 more_difficult_league()
的结果
有一个静态的生命周期(当我们提到 s1
时情况并非如此
或 s2
,编译器会抱怨),我们可以引入
此结果的新生命周期注释并指定
参数的生命周期必须超过这个结果(
where
子句)。
#[derive(Debug)]
struct Stats<'a> {
league: &'a str,
}
const NAME: &str = "rust";
fn more_difficult_league<'a, 'b, 'c>(
s1: &'a Stats,
s2: &'b Stats,
) -> &'c str
where
'a: 'c,
'b: 'c,
{
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let st = Stats { league: NAME };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}
我对 Rust 生命周期的学习过程是这样的(基于 Rust 书):
- 我想注释,当引用后面的值超出范围时
- 通常(不总是!参见 .data 部分,即“静态”)值位于
{}
块中 - 我们注释像
't: {…}
这样的块,例如结构字段的生命周期类似于&'t ident
,具有相同的生命周期名称t
- 这个理解是错误的。为什么?结构实现者很可能不知道块名称定义,并且同一结构可能有多个块名称定义。
- 所以定义
't: {…}
和用法&'t ident
必须完全独立 - 编译器可以轻松确定定义,因此用户无需编写
't: {…}
。程序员只需要关心&'t ident
规范部分。 - 编译器可以分析函数体(在
struct
的情况下:使用结构成员)并确定&'t ident
部分。 - 这个理解是错误的。为什么?因为有时候函数体(或者struct成员的使用)还不可用(比如一个trait指定了一个函数,但是实现是由其他人在未来完成的)。
- 因此,
struct
和fn
必须分别在其结构定义或函数签名中完全指定生命周期。 - 规范大多遵循相同的启发式规则。所以我们引入了生命周期省略。它根据针对最常见用例的规则插入生命周期,我们可以随时选择退出。
在这一点上,我认为我的理解非常接近它的实际工作原理。但是现在,我的理解出错了。让我们看一些例子:
#[derive(Debug)]
struct Stats {
league: &str,
}
const NAME: &str = "rust";
fn more_difficult_league(s1: &Stats, s2: &Stats) -> &str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let mut st = Stats { league: name };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}
显然,我省略了任何生命周期规格。
结构字段的生命周期要么是程序的整个持续时间(
'static
),要么与结构(Stats<'a>
和league: &'a str
)一样长在 function/method 中,我们可能会得到生命周期为
'a
、'b
、'c
、……的引用。 return 值的生命周期是多少?- 要么是某个静态值(
'static
) - 要么总是相同的特定生命周期(如
'c
) - 它要么是一个特定的生命周期 - 哪个生命周期将在编译时或 运行 时已知。对于编译器,我们必须指定最坏情况下的生命周期
max('a, 'b, 'c, …)
。据我所知,这可以通过为每个参考提供相同的生命周期来完成。
- 要么是某个静态值(
这似乎适用于以下人为设计的较短函数:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'a str {
if s1.league == s2.league {
s1.league
} else {
s2.league
}
}
如果我们添加一些 'static
return 值,最坏情况下的生命周期是 max('a, 'static)
,大概是 'static
:
fn more_difficult_league<'a>(s1: &'a Stats, s2: &'a Stats) -> &'static str {
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
这为 s2.league
提供了 error[E0621]: explicit lifetime required in the type of s1
和 lifetime 'static required
。
我的理解错在哪里?在此先感谢您的耐心等待。
免责声明: help: add explicit lifetime 'static to the type of s1: &'a Stats<'static>
可以在这里工作,但我觉得不对。
我会按照下面提供的方式更改您的代码。
而不是假装 more_difficult_league()
的结果
有一个静态的生命周期(当我们提到 s1
时情况并非如此
或 s2
,编译器会抱怨),我们可以引入
此结果的新生命周期注释并指定
参数的生命周期必须超过这个结果(
where
子句)。
#[derive(Debug)]
struct Stats<'a> {
league: &'a str,
}
const NAME: &str = "rust";
fn more_difficult_league<'a, 'b, 'c>(
s1: &'a Stats,
s2: &'b Stats,
) -> &'c str
where
'a: 'c,
'b: 'c,
{
if s1.league == s2.league {
s1.league
} else if s1.league == "PHP" {
s2.league
} else {
"C++"
}
}
fn main() {
let st = Stats { league: NAME };
let dleague = more_difficult_league(&st, &st);
println!("{}", dleague);
}