我试图更好地了解Rust的寿命。
struct Name<'a> {
arg: &'a u8,
}
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Name<'a> {
Name { arg }
}
fn new2<'b>(arg: &'b u8) -> Name<'b> {
Name { arg }
}
}
函数new1
和new2
之间是否有区别?我假设arg
是&self
会很重要吗?在任何情况下都倾向于采用new2
实施还是采用其他方式?
答案 0 :(得分:1)
这两种方法最终完全相同,但是值得学习为什么。一路上,我们将学习终生胁迫
如果第二个生命周期比第一个生命周期短(或包含在第一个生命周期中),则可以将其强制转换为另一个生命周期。通常用'a: 'b
表示,这意味着生存期'a
完全包围了生存期'b
。常用术语是'a
比'b
寿命更长。这种强制的原因是,如果需要,您总是可以缩短寿命。如果引用在某个生命周期内有效,那么它在较长生命周期中包含的任何较短生命周期中也有效。
因此,考虑到这一点,new1
和new2
可以采用哪种参数?我们有一个固定的生存期'a
,因为整个实现在该生存期中都是通用的。但是,new1
不仅可以使用&'a u8
,而且可以将&'b u8
强制为'b
的任何'a
。也就是说,'b: 'a
和'b
比'a
长。
new2
稍有不同,但最终效果相同。该方法在生命周期'b
中是通用的,如果使用&'c u8
,则可以采用任何'c: 'b
。 new2
在'a
中在技术上仍然是通用的,但是由于它根本不使用'a
,因此可以忽略。就是说,忽略通用参数会造成混淆(为什么根本没有参数?),所以最好使用new1
。
相对于new1
更喜欢new2
的另一个原因是它更适合Self
。如果我们尝试将输出更改为Self
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Self {
Name { arg }
}
fn new2<'b>(arg: &'b u8) -> Self {
Name { arg }
}
}
编译器抱怨。为什么?现在输出必须为Name<'a>
,在new2
中,我们将返回Name<'b>
。除非Name<'a>
,否则这对'b: 'a
来说是不可强制的,因此我们必须将其添加为'b
的约束:
impl<'a> Name<'a> {
fn new1(arg: &'a u8) -> Self {
Name { arg }
}
fn new2<'b: 'a>(arg: &'b u8) -> Self {
Name { arg }
}
}
在这种情况下,很明显new1
是优越的,因为它甚至不需要第二个生命周期,但仍然允许完全相同的输入。