如何为涉及对中间局部变量的引用的闭包指定生命周期边界?
How to specify lifetime bounds for a closure involving references to intermediate local variables?
我正在尝试用 Rust 编写如下函数:
fn double_and_square<'a, T>(x: &'a T) -> /* whatever the output type of `&t * &t` is */ {
let t = x + x;
&t * &t
}
我希望它适用于 T
非 Copy
的类型。我不仅需要指定 &'a T
实现 Add
(简单),还需要指定对其输出类型的引用以及局部变量 t
的生命周期实现 Mul
.
尝试 #1(没有为中间类型指定生命周期):
fn double_and_square<'a, T>(x: &'a T) -> <&<&'a T as Add>::Output as Mul>::Output
where
&'a T: Add,
&<&'a T as Add>::Output: Mul,
{
let t = x + x;
&t * &t
}
导致以下编译器错误:
error[E0106]: missing lifetime specifier
--> src/main.rs:6:5
|
6 | &<&'a T as Add>::Output: Mul,
| ^ expected lifetime parameter
尝试 #2(好的,我将添加生命周期说明符):
fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
where
&'a T: Add,
&'b <&'a T as Add>::Output: Mul,
{
let t = x + x;
&t * &t
}
导致以下编译器错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:8:13
|
8 | let t = x + x;
| ^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: ...so that expression is assignable (expected &T, found &'a T)
--> src/main.rs:8:13
|
8 | let t = x + x;
| ^
note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: ...so that the type `<&T as std::ops::Add<&'a T>>::Output` is not borrowed for too long
--> src/main.rs:9:10
|
9 | &t * &t
| ^^
error[E0490]: a value of type `<&T as std::ops::Add<&'a T>>::Output` is borrowed for too long
--> src/main.rs:9:10
|
9 | &t * &t
| ^^
|
note: the type is valid for the lifetime 'b as defined on the function body at 3:1
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: but the borrow lasts for the lifetime 'a as defined on the function body at 3:1
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
我阅读 the lifetime must be valid for the lifetime 'b as defined on the function body
的方式告诉我编译器认为 'b
应该与整个函数体一样长或更长,而我只是希望它意味着 "any lifetime".
我想做的事情在 Rust 中是否可行?如果没有,是否有任何我应该注意的建议更改可以实现?
系好安全带...
use std::ops::{Add, Mul};
fn double_and_square<'a, T, R>(x: &'a T) -> R
where
&'a T: Add,
for<'b> &'b <&'a T as Add>::Output: Mul<Output = R>,
{
let t = x + x;
&t * &t
}
很简单,对吧? ;-)
让我们一步步来...
您希望接收对类型的引用,但 引用 需要实现 Add
。 where
子句允许您在 :
的任一侧编写复杂类型,因此我们使用 &'a T: Add
.
这将 return 我们再次引用的一些值。但是,double_and_square
的 caller 无法指定生命周期,因为它仅存在于函数内部。这意味着我们需要使用 higher-ranked trait bound: for <'b>
.
我们要使用Add
操作的输出类型,说它实现了Mul
,输出类型是通用的R
.
我建议不要在原始函数中引用,因为它更容易理解:
fn double_and_square<T, R>(x: T) -> R
where
T: Add + Copy,
for<'a> &'a T::Output: Mul<Output = R>,
{
let t = x + x;
&t * &t
}
&Foo
是一个独立于Foo
的类型,可以作为T
的具体类型传递,所以这应该可以可以在原件所在的任何地方使用,并且可能在更多情况下可用。
I want it to work on types where T
is non-Copy
对类型的不可变引用总是 Copy
,即使类型本身没有实现 Copy
。因此,您可以使用例如调用此函数T = i32
或一个T = &NonCopy
。 仅接受引用的原始情况将只接受第二个。
在理想情况下,您可以避免泛型类型 R
,而只说 <...something...>::Output
,但据我所知,目前这是不可能的。
我正在尝试用 Rust 编写如下函数:
fn double_and_square<'a, T>(x: &'a T) -> /* whatever the output type of `&t * &t` is */ {
let t = x + x;
&t * &t
}
我希望它适用于 T
非 Copy
的类型。我不仅需要指定 &'a T
实现 Add
(简单),还需要指定对其输出类型的引用以及局部变量 t
的生命周期实现 Mul
.
尝试 #1(没有为中间类型指定生命周期):
fn double_and_square<'a, T>(x: &'a T) -> <&<&'a T as Add>::Output as Mul>::Output
where
&'a T: Add,
&<&'a T as Add>::Output: Mul,
{
let t = x + x;
&t * &t
}
导致以下编译器错误:
error[E0106]: missing lifetime specifier
--> src/main.rs:6:5
|
6 | &<&'a T as Add>::Output: Mul,
| ^ expected lifetime parameter
尝试 #2(好的,我将添加生命周期说明符):
fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
where
&'a T: Add,
&'b <&'a T as Add>::Output: Mul,
{
let t = x + x;
&t * &t
}
导致以下编译器错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:8:13
|
8 | let t = x + x;
| ^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: ...so that expression is assignable (expected &T, found &'a T)
--> src/main.rs:8:13
|
8 | let t = x + x;
| ^
note: but, the lifetime must be valid for the lifetime 'b as defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: ...so that the type `<&T as std::ops::Add<&'a T>>::Output` is not borrowed for too long
--> src/main.rs:9:10
|
9 | &t * &t
| ^^
error[E0490]: a value of type `<&T as std::ops::Add<&'a T>>::Output` is borrowed for too long
--> src/main.rs:9:10
|
9 | &t * &t
| ^^
|
note: the type is valid for the lifetime 'b as defined on the function body at 3:1
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
note: but the borrow lasts for the lifetime 'a as defined on the function body at 3:1
--> src/main.rs:3:1
|
3 | / fn double_and_square<'a, 'b, T>(x: &'a T) -> <&'b <&'a T as Add>::Output as Mul>::Output
4 | | where
5 | | &'a T: Add,
6 | | &'b <&'a T as Add>::Output: Mul,
... |
9 | | &t * &t
10| | }
| |_^
我阅读 the lifetime must be valid for the lifetime 'b as defined on the function body
的方式告诉我编译器认为 'b
应该与整个函数体一样长或更长,而我只是希望它意味着 "any lifetime".
我想做的事情在 Rust 中是否可行?如果没有,是否有任何我应该注意的建议更改可以实现?
系好安全带...
use std::ops::{Add, Mul};
fn double_and_square<'a, T, R>(x: &'a T) -> R
where
&'a T: Add,
for<'b> &'b <&'a T as Add>::Output: Mul<Output = R>,
{
let t = x + x;
&t * &t
}
很简单,对吧? ;-)
让我们一步步来...
您希望接收对类型的引用,但 引用 需要实现
Add
。where
子句允许您在:
的任一侧编写复杂类型,因此我们使用&'a T: Add
.这将 return 我们再次引用的一些值。但是,
double_and_square
的 caller 无法指定生命周期,因为它仅存在于函数内部。这意味着我们需要使用 higher-ranked trait bound:for <'b>
.我们要使用
Add
操作的输出类型,说它实现了Mul
,输出类型是通用的R
.
我建议不要在原始函数中引用,因为它更容易理解:
fn double_and_square<T, R>(x: T) -> R
where
T: Add + Copy,
for<'a> &'a T::Output: Mul<Output = R>,
{
let t = x + x;
&t * &t
}
&Foo
是一个独立于Foo
的类型,可以作为T
的具体类型传递,所以这应该可以可以在原件所在的任何地方使用,并且可能在更多情况下可用。
I want it to work on types where
T
is non-Copy
对类型的不可变引用总是 Copy
,即使类型本身没有实现 Copy
。因此,您可以使用例如调用此函数T = i32
或一个T = &NonCopy
。 仅接受引用的原始情况将只接受第二个。
在理想情况下,您可以避免泛型类型 R
,而只说 <...something...>::Output
,但据我所知,目前这是不可能的。