- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在下面的一段代码中,我试图了解通用生命周期参数 'a
是专业的。
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0; // the lifetime of x, call it 'x, starts from here |
r = Wrapper(&x); // 'a parameter in Wrapper is specialized to 'x |
drop(r); // |
} // --------------------------------- 'x ends here |
{
let y = 0; // the lifetime of y, call it 'y, starts from here |
// 'y is distinct from 'x |
// neither outlives the other one |
r = Wrapper(&y); // why 'a parameter can again be specialized to 'y? |
drop(r); // |
} // ------------------------------------ 'y ends here |
}
为什么可能是通用生命周期参数
'a
可以专门用于两个不相交的生命周期
'x
和
'y
, 一个对象
'r
?
r
的具体类型很困惑。 .来自
subtyping and variance Rustonomicon 一章,我明白生命周期
'a
是泛型类型
Wrapper<'a>
的一部分.当泛型被专门化时,它不能是
Wrapper<'x>
也不是
Wrapper<'y>
.那么
r
的类型是什么? ?
r
的生命周期可以有多个起点和终点。如果这是真的,那么
'r
是
'x
的并集和
'y
.然而,这种解释与
subtyping 不太吻合。规则。例如,考虑以下代码,
'r2
也不是
'r
是另一个的子类型(或生命周期更长),所以我们不应该调用
bar(r, r2)
,但我们实际上可以。矛盾。
struct Wrapper<'a>(&'a i32);
fn bar<'a>(_p: Wrapper<'a>, _q: Wrapper<'a>) {}
fn foo() {
let mut r;
{
let z = 0;
let r2 = Wrapper(&z); // -> |
{ // |
let x = 0; // -> | // +--'r2
r = Wrapper(&x); // |--'x--+ // |
bar(r, r2); // | | // <- |
} // <- | |
} // |
{ // +--'r
let y = 0; // -> | |
r = Wrapper(&y); // |--'y--+
drop(r); // |
} // <- |
}
最佳答案
你在以错误的方式思考人生。 r
的生命周期没有被专门研究 'x
也不是 'y
.它有自己的生命周期(我们称之为 'r
)。
如 Non-Lexical Lifetimes RFC 中所述,值的生命周期(或 RFC 所称的范围)是程序中该值在 future 仍可使用的点。至关重要的是,生命周期不一定是线性的,也不必适合特定的语法范围(即 {}
块)。此外,生命周期不连接到变量(如 r
),而是它们绑定(bind)到的值。因此,如果您分配给一个变量(即 r = ..
),您实际上会杀死一个值并开始另一个值。它不算作使用。但是,分配给值的成员(即 r.0 = ..
)是一种用法,因为您正在更改现有值的一小部分。
在您的情况下,'r
有两个起点和两个终点。第一个起点是r = Wrapper(&x);
第一个端点位于第一个 drop(r)
.第二个起点和终点在 y 块中。可视化:
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0;
r = Wrapper(&x); // -> |
// |--'x--+
drop(r); // <- | |
} // |
{ // +--'r
let y = 0; // |
r = Wrapper(&y); // -> | |
// |--'y--+
drop(r); // <- |
}
}
这里我也插入了
'x
和
'y
以供引用。注意如何
'r
特别是不在两个范围之间。
'a: 'b
(
'a
必须比
'b
生命周期长)。对于此绑定(bind),任何地方
'b
正在直播,
'a
也必须直播。这就是outlives的意思。另一种说法:
'a
lasts longer than 'b
.
'a
only needs to outlive 'b
starting from the point their relation begins.
r = Wrapper(&'x x)
的声明(我添加了生命周期以供引用)借用检查器必须确保引用的生命周期
&'x x
比
r
的生命周期长(即
'x: 'r
)从
r = Wrapper(&x)
开始.查看上面的生命周期,我们可以看到任何地方
'x
已上线,也是
'r
.
'x
当范围结束时死亡,但幸运的是,
'r
也是如此.所以这个检查。冲洗并重复
'y
.
drop
打电话看看它是否有所作为:
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0;
r = Wrapper(&x);
}
{
let y = 0;
r = Wrapper(&y);
}
}
这不会改变任何生命周期。请记住,生命周期与将来是否会使用值有关。由于我们还没有添加
r
的任何用途,
x
, 或
y
,没有生命周期改变。
x
怎么办?不在范围内:
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
let x = 0;
r = Wrapper(&x);
{
let y = 0;
r = Wrapper(&y);
}
}
这里
'r
和
'x
已移入父作用域,但除此之外它们都与原始示例非常相似。同样与
'y
.因此所有的界限仍然成立,并且
it compiles .
y
也是一样的.
r
的一些用途.如果我们不创建一个新的
Wrapper
会怎样?为
y
,我们只需覆盖引用:
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0;
r = Wrapper(&x);
}
{
let y = 0;
r.0 = &y;
}
}
这将发生重大变化
'r
,因为在第一个作用域之后,它将在第二个作用域中使用以分配一个新的引用。因此,
'r
现在跨越
r = Wrapper(&x)
至
r.0 = &y
.然而,
'x
无法匹配,如
x
活得不够长(超出范围)。因此,我们应该得到一个错误消息
x
活得不够久,
which we do .
r
呢?在两个范围之后:
#[derive(Debug)]
struct Wrapper<'a>(&'a i32);
fn foo() {
let mut r;
{
let x = 0;
r = Wrapper(&x);
}
{
let y = 0;
r = Wrapper(&y);
}
println!("{:?}", r)
}
在这里,
'r
现在比原始示例稍大,在
r = Wrapper(&y)
之后继续到达打印品。但是,它仍然不在两个块之间,因为在第一个范围中分配的值从未在第二个范围中使用过。因此,
'x
活下去
'r
.然而,
'y
现在需要足够大以达到打印(因为
'r
这样做),它不能,因为
y
将超出范围。因此,编译器应该提示
y
活得不够久,但不说
x
.幸运的是,
that is the case .
fn some_fn<'a>(a: &'a i32, b: &'a i32)
,为什么我们可以传递两个生命周期不同的这个函数的引用。似乎函数声明在两种情况下都需要完全相同的生命周期。
Whenever references are copied from one location to another, the Rust subtyping rules require that the lifetime of the source reference outlives the lifetime of the target location.
'a
是对
bar
的调用的生命周期.路过时
r
和
r2
到它,我们得到了边界
'r: 'a
和
'r2: 'a
.这使它变得非常容易,因为
'a
只在通话期间活着,其他的生命也都活着。在调用之后,所有三个生命周期都已死亡,因此绑定(bind)变得微不足道。
关于rust - 为什么 Rust 中的通用生命周期参数可以专门用于一个对象的两个不相交的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67632034/
我有一个带有模板函数的基类,该函数具有通用模板类型和专用版本。 #ifndef BASE_CLASS #define BASE_CLASS #include using namespace std;
我有这个 3D vector 模板 template class Vec3TYPE{ public: union{ struct{ TYPE x,y,z; }; struct{ TY
我是一名优秀的程序员,十分优秀!