fn the_longest<'a, 'b: 'a>(s1: &'a str, s2: &'b str) -> &'a str {
if s1.len() > s2.len() {
s1
} else {
s2
}
}
fn main() {
let s1 = String::from("rust");
let s1_r = &s1;
{
let s2 = String::from("C");
let res = the_longest(s1_r, &s2);
let res = the_longest(&s2, s1_r);
println!("{} is the longest string", res);
}
}
问题:
- 'a 'b 跟参数传参的顺序有没有关系?
- main 函数中调用了2次 the_longest,参数顺序不一样,为什么能编译通过?是否说明问题1生命周期跟参数顺序没关?如果跟参数顺序没关系,那 'a 'b 代表的不是入参的生命周期,那代表的是什么?
1
共 6 条评论, 1 页
评论区
写评论手打的。
感谢回答。我在理解一下
顺便问一句,作用域的这种图是怎么画的
--
👇
苦瓜小仔: 首先你得分清生命周期、生命周期标注两个事情,其次你所指的生命周期是值的还是引用的?
对于 'a 和 'b,它们是函数上的生命周期标注,最重要的是表明多个生命周期之间约束关系(谁应该比谁活得更长[^1],或者说,谁不能在谁之前无效)。
[^1]: 注意,x 比 y 活得更长 ('x: 'y 或者说 'x outlives 'y) 是 x 的生命周期大于等于 y 的生命周期,而不是 x 的生命周期严格大于 y 的生命周期
而值的生命周期通常不会觉得混乱,因为 它就是一个值的作用域,从创建到释放的范围。
引用的生命周期就是引用有效的范围,它可以有洞(非连续的)。
以下是 s1 和 s2 的值的范围及产生的引用
注意,&'y s2 和 &'z s2 是临时的、传给函数的引用。'z 的有效范围不仅在
the_longest
函数内有效,并且可以延续到函数体之外(因为 the_longest 的生命周期标注)。而生命周期标注
<'a, 'b: 'a>(s1: &'a str, s2: &'b str) -> &'a str
作为一种契约,规定了以下内容:那么我猜让你最困惑的点在于,对于
the_longest(s1_r, &s2)
,似乎不符合上述第一个约定 —— &s2 完全可以并且的确先于第一个引用无效之前无效。这就涉及再借 (reborrow) 与型变 (variance):
the_longest(s1_r, &s2)
实际上是the_longest(&*s1_r, &s2)
,其中&*s1_r
的生命周期比s1_r
更小。&*s1_r
通过协变,可以被视为和&s2
一样的生命周期(甚至比 &s2 更小生命周期),从而符合第一个约定。感谢回答。我在理解一下
--
👇
zylthinking: 额, 还有个前提, 就是你这代码
fn the_longest<'a, 'b: 'a>(s1: &'a str, s2: &'b str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 } }
其实编译器知道和下面的比, 除了适用情况更广外, 没有副作用
fn the_longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 } }
于是实际上, 它就能将上面的代码当作下面的代码来处理
--
👇
zylthinking: 这里有个概念叫做协变, 理解了这个就一切清楚了 https://doc.rust-lang.org/nomicon/subtyping.html
首先你得分清生命周期、生命周期标注两个事情,其次你所指的生命周期是值的还是引用的?
对于 'a 和 'b,它们是函数上的生命周期标注,最重要的是表明多个生命周期之间约束关系(谁应该比谁活得更长[^1],或者说,谁不能在谁之前无效)。
[^1]: 注意,x 比 y 活得更长 ('x: 'y 或者说 'x outlives 'y) 是 x 的生命周期大于等于 y 的生命周期,而不是 x 的生命周期严格大于 y 的生命周期
而值的生命周期通常不会觉得混乱,因为 它就是一个值的作用域,从创建到释放的范围。
引用的生命周期就是引用有效的范围,它可以有洞(非连续的)。
以下是 s1 和 s2 的值的范围及产生的引用
注意,&'y s2 和 &'z s2 是临时的、传给函数的引用。'z 的有效范围不仅在
the_longest
函数内有效,并且可以延续到函数体之外(因为 the_longest 的生命周期标注)。而生命周期标注
<'a, 'b: 'a>(s1: &'a str, s2: &'b str) -> &'a str
作为一种契约,规定了以下内容:那么我猜让你最困惑的点在于,对于
the_longest(s1_r, &s2)
,似乎不符合上述第一个约定 —— &s2 完全可以并且的确先于第一个引用无效之前无效。这就涉及再借 (reborrow) 与型变 (variance):
the_longest(s1_r, &s2)
实际上是the_longest(&*s1_r, &s2)
,其中&*s1_r
的生命周期比s1_r
更小。&*s1_r
通过协变,可以被视为和&s2
一样的生命周期(甚至比 &s2 更小生命周期),从而符合第一个约定。额, 还有个前提, 就是你这代码
fn the_longest<'a, 'b: 'a>(s1: &'a str, s2: &'b str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 } }
其实编译器知道和下面的比, 除了适用情况更广外, 没有副作用
fn the_longest<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s1.len() > s2.len() { s1 } else { s2 } }
于是实际上, 它就能将上面的代码当作下面的代码来处理
--
👇
zylthinking: 这里有个概念叫做协变, 理解了这个就一切清楚了 https://doc.rust-lang.org/nomicon/subtyping.html
这里有个概念叫做协变, 理解了这个就一切清楚了 https://doc.rust-lang.org/nomicon/subtyping.html