如何指定涉及对中间局部变量的引用的闭包的生存期界限? [英] How to specify lifetime bounds for a closure involving references to intermediate local variables?

查看:60
本文介绍了如何指定涉及对中间局部变量的引用的闭包的生存期界限?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Rust中编写类似以下的函数:

I'm trying to write a function like the following in 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.

I want it to work on types where T is non-Copy. I need to specify not only that &'a T implements Add (easy), but also that a reference to its output type with the lifetime of local variable t implements Mul.

尝试#1 (未为中间类型指定生存期):

Attempt #1 (no lifetime specified for the intermediate type):

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 (好的,我将添加一个生存期说明符):

Attempt #2 (alright, I'll add a lifetime specifier):

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应该生存的时间比整个函数体长或更长,而我只希望它的意思是任何生命周期".

The way that I read the lifetime must be valid for the lifetime 'b as defined on the function body tells me the compiler thinks 'b is supposed to live as long as or longer than the whole function body, whereas I just want it to mean "any lifetime".

我正在Rust中尝试做的事情吗?如果没有,我应该注意是否有任何建议的更改将使之成为可能?

Is what I'm trying to do even possible in Rust? If not, are there any proposed changes I should watch that will make it possible?

推荐答案

锁定...

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
}

很容易,对吧? ;-)

Easy enough, right? ;-)

让我们一步一步来吧...

Let's take it step by step...

  1. 您希望接受对类型的引用,但是 reference 需要实现Add. where子句使您可以在:的任一侧编写复杂类型,因此我们使用&'a T: Add.

  1. You wish to take in a reference to a type, but the reference needs to implement Add. where clauses let you write complex types on either side of the :, so we use &'a T: Add.

这将返回一些值,我们将再次引用该值.但是,double_and_square caller 无法指定生存期,因为它仅存在于函数内部.这意味着我们需要使用高阶特质绑定:for <'b>.

This will return some value that we take another reference to. However, the caller of double_and_square cannot specify the lifetime, since it only exists inside the function. This means we need to use a higher-ranked trait bound: for <'b>.

我们必须使用Add操作的输出类型,假设它实现了Mul,并且输出类型是通用的R.

We have to use the type of the output of the Add operation, say that it implements Mul, and the output type is the generic R.


我建议不要在原始函数中使用引用,因为它更易于理解:


I'd recommend not taking references in the original function as it's way easier to understand:

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的具体类型传递,因此它应该可以在原始文件的任何地方使用,并且也许在更多情况下可用.

&Foo is a separate type from Foo and can be passed as the concrete type of T, so this should be able to be used in any place the original was, and probably usable in even more cases.

我希望它在T不是-Copy

对类型的不可变引用始终为Copy,即使类型本身未实现Copy.因此,您可以通过以下方式调用此函数: T = i32 一个T = &NonCopy. only 仅接受引用的原始情况将仅接受第二种情况.

Immutable references to types are always Copy, even if the type itself doesn't implement Copy. Thus, you can call this function with e.g. T = i32 or a T = &NonCopy. The original case that only accepted references would only accept the second one.

在理想的世界中,您可以避免使用通用类型R,而只需说<...something...>::Output,但据我所知,目前尚不可能.

In an ideal world, you'd be able to avoid the generic type R and just say <...something...>::Output, but as far as I know that's not currently possible.

这篇关于如何指定涉及对中间局部变量的引用的闭包的生存期界限?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆