String::push_str 和 Vec::push 在生命周期约束方面有什么区别?

问题描述 投票:0回答:1
struct V<'a> {
    s: &'a mut String,
    v: Vec<&'a String>
}

impl<'a, 'b> V<'a> {
    pub fn set(&mut self, s: &'b String){
        // self.s = s;
        self.s.push_str(s);
        self.v.push(s);
    }
}
error: lifetime may not live long enough
  --> src/main.rs:68:9
   |
64 | impl<'a, 'b> V<'a> {
   |      --  -- lifetime `'b` defined here
   |      |
   |      lifetime `'a` defined here
...
68 |         self.v.push(s);
   |         ^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
   |
   = help: consider adding the following bound: `'b: 'a`

但是

self.s.push_str(s);
还可以。它们的函数签名是相同的 (
fn xxx(&mut self, &...)
)。是什么原因?我读了这篇2094-nll文章,但我仍然很困惑。

rust lifetime
1个回答
2
投票

它们的函数签名是相同的( fn xxx(&mut self, &...) )。

让我们来看看这个说法。

1.
String::push_str

pub fn push_str(&mut self, string: &str)

它需要一个

&str
,又名一片(utf-8 编码)字节,没有额外的生命周期要求。

String
具有隐式
Deref
&str
 的转换。

对于我们提供的参数 (

s: &'b String

),这会导致 
&'b str
。我们可以毫无问题地调用 
push_str
,因为它的参数没有生命周期要求。

2.

Vec::push

pub fn push(&mut self, value: T)

T

 绑定到 
&'a String
Vec
 的通用参数)时,变成 

pub fn push(&mut self, value: &'a String)
它需要一个 

&'a String

,又名对 a 的引用
String
 生命周期至少与 
'a
 一样长的对象。

我们提供的论点再次是

s: &'b String

。
生命周期 
'b
 没有声明它与 
'a
 的关系,因此编译器不能假设它更长。因此,编译器拒绝接受 
s: &'b String
 来代替 
s: &'a String

解决此问题的一个方法(正如编译器善意建议的那样)是要求生命周期有这样的限制

'b

impl<'a, 'b: 'a> V<'a> { pub fn set(&mut self, s: &'b String){ self.s.push_str(s); self.v.push(s); } }
或者,更常见的写法(因为 

'b

 与我们的 
Vec
 无关):

impl<'a> V<'a> { pub fn set<'b: 'a>(&mut self, s: &'b String){ self.s.push_str(s); self.v.push(s); } }
最后,生命周期

'b

在这里实际上是完全没有必要的。
您可以在任何地方使用 
'a
。 (对于函数参数,生命周期始终是最小界限)。

impl<'a> V<'a> { pub fn set(&mut self, s: &'a String){ self.s.push_str(s); self.v.push(s); } }
( 

演示 )

© www.soinside.com 2019 - 2024. All rights reserved.