What's the difference between `T: Trait + 'a` and `impl Trait + 'a`?

I originally thought T: 'a will restrict you from using T instance outside 'a because this exmaple reports an error:

fn main() {
    let num;
    {
        let num1 = 10; // error: num1 doesn't live long enough
        num = test(&num1);
    }
    println!("num: {}", num);

fn test<'a, T: Copy + Display>(para: &'a T) -> impl Copy + Display + 'a {
    *para
}

However, if you change the example to:

fn main() {
    let num;
    {
        let num1 = 10;
        num = test(&num1);
    }
    println!("num: {}", num);
}

fn test<'a, T: Copy + Display + 'a>(para: &'a T) -> T {
    *para
}

Now everythig is OK... So what's the difference?

PS: The idea that T: 'a will restrict you form using T instance outside 'a comes from this example:

fn say_some<'a>(name: String) -> impl Fn(&'a str) + 'a {
    move |text| println!("{name} syas: {text}")
}

fn main() {
    let func = say_some("Blackbird".into());
    {
        let string: String = "Talk is cheap.".into();
        let r = &string; // error: string doesn't live long enough
        func(r);
    }
}

This could be solved by changing impl Fn(&'a str) + 'a to impl Fn(&'a str) + 'static.

In the second example substitute i32 for T and you get a function &'a i32 -> i32. The constraint is telling you the substitution is legal (because i32: 'a trivially).

But in the first example, when you substitute i32 in you get &'a i32 -> impl .... The type of the function is different as the return type has been erased. Even though it "is" i32, you are only allowed to use what the impl says and you've lost the fact that i32: 'static.

FWIW, in your first example, the code will compile, if you replace 'a with use<T> in the RPIT.

The difference are different types. When you write T that means… well, T.

When you write impl Trait in return position then creates something Haskell calls an existential type: that may still be T, under the hood, but you are not permitted to use that.

The rest of your code may only use functions from Trait and, if you added + 'a or use<T> it would be able to use for 'a (or for as long as T exists).

Because reference to type may have smaller lifetime than type itself (trivial example: i32: 'a for any 'a) impl T + 'a and impl T + use<T> are usable for a different lifetimes (that's actually why new use<T> syntax exists, before it's introduction there was not possible to express that desire).

Some more info on abstract return types from the reference.

@user16251 @khimru

Thanks for all your reply! Both help me a lot.

In my first example, ra shows the type of num as impl Copy + Display. Rustc only knows type of num implements Copy and Display and satisfies Type: 'a. From the view of rustc, the actual type of num may be i32, &i32 or something else. In order to avoid dangling pointer, borrow checker has to restrict me from using num outside 'a which is inferred to not exceed scoop of num1.

In my second example, rustc knows num is i32. It can be used safely.