为什么 Rust 借用检查器不能利用“静态”边界?
Why can't the Rust borrow checker take advantage of `'static` bounds?
#![feature(generic_associated_types)]
pub trait Func {
type Input<'a>;
type Output;
fn call(self, input: Self::Input<'_>) -> Self::Output;
}
fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
where F: 'static + Func<Input<'cx> = &'cx u8, Output = u8>,
{
let input = &*ctx;
let out = f.call(input);
*ctx = out;
}
我用过 #![feature(generic_associated_types)]
,但我认为如果您将 'a
从 Func::Input
移动到 Func
并使用invoke
.
上的高阶特征绑定
这段代码有误,但我认为它没有问题:
error[E0506]: cannot assign to `*ctx` because it is borrowed
--> src/lib.rs:15:5
|
10 | fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
| --- lifetime `'cx` defined here
...
13 | let input = &*ctx;
| ----- borrow of `*ctx` occurs here
14 | let out = f.call(input);
| ------------- argument requires that `*ctx` is borrowed for `'cx`
15 | *ctx = out;
| ^^^^^^^^^^ assignment to borrowed `*ctx` occurs here
首先 ctx
被重新借用为 input
,它被传递给 f.call
然后再也没有使用过。 f.call
returns一个不包含任何生命周期的值(u8: 'static
),所以out
和ctx
之间没有联系。
同样,f
的类型不包含生命周期 (F: 'static
),因此它不能包含生命周期为 'cx
的引用。此外,无法将生命周期 'cx
安全地强制转换为 call
内的 'static
,因此无法“走私”具有该生命周期的引用,该引用可以在调用 [=19= 之外访问].因此,我看不出有什么可以别名 ctx
,我认为在最后一行分配给它应该是合理的。
我错过了什么吗?接受这个代码是不合理的吗?如果不是,为什么 Rust 无法以这种方式利用 'static
边界?
生命周期 'cx
可能是 'static
意味着 input
可以 被走私到别处并被 *ctx = out
无效。
无法限制生命周期严格小于另一个生命周期,因此我认为借用检查器甚至不会考虑向泛型类型添加“更广泛”的生命周期约束。
写的代码不合理。 F
上 'static
的生命周期边界完全无关紧要,因为 F::Input
和 F
的生命周期边界是两个不同的生命周期,导致错误的是关联类型的生命周期.通过声明 F::Input<'ctx> = &'ctx u8
,您声明不可变借用的寿命与可变引用的长度相同,从而使可变引用使用不安全。
正如@Stargateur 所提到的,可以使这项工作起作用的是更高等级的特征范围:
fn invoke<F>(f: F, ctx: &mut u8)
where F: for<'ctx> Func<Input<'ctx> = &'ctx u8, Output = u8>,
{
let input = ctx;
let out = f.call(input);
*input = out;
}
也就是说,不是声明函数调用在某个特定生命周期 'ctx
内有效,而是在所有生命周期 'ctx
内都有效。这样,编译器可以自由地为重新借用选择合适的生命周期来完成这项工作。
附带说明一下,您可能认为在函数定义中使用两个特定的生命周期是可行的,但任何这样做的尝试都会导致编译器 failing to choose 使事情正常进行的适当生命周期.
#![feature(generic_associated_types)]
pub trait Func {
type Input<'a>;
type Output;
fn call(self, input: Self::Input<'_>) -> Self::Output;
}
fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
where F: 'static + Func<Input<'cx> = &'cx u8, Output = u8>,
{
let input = &*ctx;
let out = f.call(input);
*ctx = out;
}
我用过 #![feature(generic_associated_types)]
,但我认为如果您将 'a
从 Func::Input
移动到 Func
并使用invoke
.
这段代码有误,但我认为它没有问题:
error[E0506]: cannot assign to `*ctx` because it is borrowed
--> src/lib.rs:15:5
|
10 | fn invoke<'cx, F>(f: F, ctx: &'cx mut u8)
| --- lifetime `'cx` defined here
...
13 | let input = &*ctx;
| ----- borrow of `*ctx` occurs here
14 | let out = f.call(input);
| ------------- argument requires that `*ctx` is borrowed for `'cx`
15 | *ctx = out;
| ^^^^^^^^^^ assignment to borrowed `*ctx` occurs here
首先 ctx
被重新借用为 input
,它被传递给 f.call
然后再也没有使用过。 f.call
returns一个不包含任何生命周期的值(u8: 'static
),所以out
和ctx
之间没有联系。
同样,f
的类型不包含生命周期 (F: 'static
),因此它不能包含生命周期为 'cx
的引用。此外,无法将生命周期 'cx
安全地强制转换为 call
内的 'static
,因此无法“走私”具有该生命周期的引用,该引用可以在调用 [=19= 之外访问].因此,我看不出有什么可以别名 ctx
,我认为在最后一行分配给它应该是合理的。
我错过了什么吗?接受这个代码是不合理的吗?如果不是,为什么 Rust 无法以这种方式利用 'static
边界?
生命周期 'cx
可能是 'static
意味着 input
可以 被走私到别处并被 *ctx = out
无效。
无法限制生命周期严格小于另一个生命周期,因此我认为借用检查器甚至不会考虑向泛型类型添加“更广泛”的生命周期约束。
写的代码不合理。 F
上 'static
的生命周期边界完全无关紧要,因为 F::Input
和 F
的生命周期边界是两个不同的生命周期,导致错误的是关联类型的生命周期.通过声明 F::Input<'ctx> = &'ctx u8
,您声明不可变借用的寿命与可变引用的长度相同,从而使可变引用使用不安全。
正如@Stargateur 所提到的,可以使这项工作起作用的是更高等级的特征范围:
fn invoke<F>(f: F, ctx: &mut u8)
where F: for<'ctx> Func<Input<'ctx> = &'ctx u8, Output = u8>,
{
let input = ctx;
let out = f.call(input);
*input = out;
}
也就是说,不是声明函数调用在某个特定生命周期 'ctx
内有效,而是在所有生命周期 'ctx
内都有效。这样,编译器可以自由地为重新借用选择合适的生命周期来完成这项工作。
附带说明一下,您可能认为在函数定义中使用两个特定的生命周期是可行的,但任何这样做的尝试都会导致编译器 failing to choose 使事情正常进行的适当生命周期.