How to specify lifetime bounds for a closure involving references to intermediate local variables?

前端 未结 1 1641
慢半拍i
慢半拍i 2021-01-18 15:53

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 *          


        
相关标签:
1条回答
  • 2021-01-18 16:08

    Buckle up...

    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. 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.

    2. 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>.

    3. 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 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.

    I want it to work on types where T is non-Copy

    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.

    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.

    0 讨论(0)
提交回复
热议问题