在Rust编程语言的第19.2章中,下面的示例编译时没有任何错误。我从第1834期中发现,有一个新的生命周期省略规则,它隐式地使's比'c更长。
虽然我无法找到这个新的省略规则的详细解释,但我猜想它不仅仅是一个更长、更显式约束:<'c, 's: 'c>的隐式版本。然而,我认为我的困惑可能不是关于这个新的省略规则,但当然,我可能是错的。
我的理解是,parse_context拥有context的所有权,因为它不是借来的,而是实际转移到函数中的。这本身就意味着,context的生存期应该与它所拥有的函数的生存期相匹配,而不管我们在Context和Parser中定义的生存期和约束。
基于这些定义,context超过临时Parser的部分对我来说是非常有意义的(毕竟,我们定义了更长的生命周期),但是当context在parse_context的末尾超出范围时,&str引用不会被删除,而我仍然可以安全地返回它--这让我感到困惑。
我错过了什么?编译器如何解释返回的&str的生存期
更新的示例
struct Context<'s>(&'s str);
struct Parser<'c, 's>
{
context: &'c Context<'s>,
}
impl<'c, 's> Parser<'c, 's>
{
fn parse(&self) -> Result<(), &'s str>
{
Err(self.context.0)
}
}
fn parse_context(context: Context) -> Result<(), &str>
{
Parser { context: &context }.parse()
}
fn main()
{
let mut s = String::new();
s += "Avail";
s += "able?";
if let Err(text) = parse_context(Context(&s))
{
println!("{}", text);
}
}发布于 2019-04-24 09:19:19
struct Context<'s>(&'s str);Context类型的→值持有一个具有某些生存期's的字符串。此生存期至少与上下文的生存期一样长,但可能更长。
struct Parser<'c, 's>
{
context: &'c Context<'s>,
}Parser类型的→值持有对具有某些生存期'c的上下文的引用。此上下文与其他生命周期's一起保存一个字符串。
impl<'c, 's> Parser<'c, 's>
{
fn parse(&self) -> Result<(), &'s str>
{
Err(self.context.0)
}
}parse函数返回一个具有生存期's的值,即。具有与上下文中存储的字符串相同的生存期,这与上下文本身的生存期不同。
fn parse_context(context: Context) -> Result<(), &str>
{
Parser { context: &context }.parse()
}我不确定这是在哪里指定的,但显然编译器推断返回的字符串的生存期与用于上下文的's参数相同。注意,尽管上下文本身被移动到parse_context中,但这只会影响上下文本身,而不会影响它包含的字符串。
fn main()
{
let mut s = String::new();main结束时,→创建一个有效的新字符串
s += "Avail";
s += "able?";
if let Err(text) = parse_context(Context(&s))parse_context创建一个新的上下文并将其移动到→中。它将自动删除在parse_context的末尾。它保存对字符串s的引用,该引用在main结束之前有效,parse_context返回一个与s⇒text有效的字符串相同的字符串,直到main结束为止。
{
println!("{}", text);
}
}无问题:text在main结束前有效。
发布于 2019-04-24 00:22:45
您是,而不是,它返回函数所拥有值的引用。您正在返回传入的引用的副本。
您的函数是身份函数的详细版本:
fn parse_context(s: &str) -> &str {
s
}在实际代码中,您将引用包含字符串切片的结构,然后再引用字符串切片,但所有这些引用都会被丢弃。
例如,在parse中有一个不必要的引用
fn parse(&self) -> Result<(), &'s str> {
Err( self.context.0)
// ^ no & needed
}此外,如果您启用了一些更多的lints,您将不得不为您的函数签名添加更多的生命周期,这可能会使事情变得更清楚:
#![deny(rust_2018_idioms)]
fn parse_context(context: Context<'_>) -> Result<(), &'_ str> {
Parser { context: &context }.parse()
}另请参阅:
虽然我找不到关于这个新的省略规则的详细解释,
版本指南中的结构中的推理。
发布于 2019-04-24 09:10:19
感谢Jmb的评论和Shepmaster的一些回答,我现在确实很清楚,我的困惑是关于RAII规则和所有权。
也就是说,该字符串是在main范围中创建的,匿名Context实例是而不是,它只是借用一个引用,因此即使在parse_context结束时,复制到Err对象的引用仍然存在并指向现有字符串--因此我们使用受约束的生存期变量,编译器能够对内部字符串引用的生存期进行推理。
https://stackoverflow.com/questions/55820491
复制相似问题