< 返回版块

TsuITOAR 发表于 2021-08-21 21:39

Tags:lifetime,compile error

结案:这是bug
impl-trait return type is bounded by all input type parameters, even when unnecessary


以下代码无法通过编译

fn foo<'a,A>(s:&'a u8,_a:A)->impl Iterator<Item=&u8>+'a{
    std::iter::once(s)
}
fn bar<'a,A>(s:&'a u8, a:A)->impl Iterator<Item=&u8>+'a{
    foo(s,a)
}
   Compiling playground v0.0.1 (/playground)
error[E0309]: the parameter type `A` may not live long enough
  --> src/main.rs:15:30
   |
15 | fn bar<'a,A>(s:&'a u8, a:A)->impl Iterator<Item=&u8>+'a{
   |           -                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `impl Iterator` will meet its required lifetime bounds
   |           |
   |           help: consider adding an explicit lifetime bound...: `A: 'a`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0309`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

但是我的foo<'a,A>(u8,A)->impl Iterator<Item=&u8>+'a函数签名并没有要求A:'a,其返回值也满足bar<'a,A>(u8,A)->impl Iterator<Item=&u8>+'a的函数签名,为什么这里还是会强制要求bar()的显示标注A:'a
下面的代码是可以编译的
edit:这个例子有误,见评论区

fn main(){
    let i:u8=1;
    let mut p;
    let r=&i;
    {
        let j=0;
        p=foo(r,j);
    }
    println!("{:?}",p.next())
}

fn foo<'a,A>(s:&'a u8,_a:A)->impl Iterator<Item=&u8>+'a{
    std::iter::once(s)
}

Playground link

评论区

写评论
作者 TsuITOAR 2021-08-22 20:46

感谢分享!

--
👇
Airtnp: 类似的issue https://github.com/rust-lang/rust/issues/79415 https://github.com/rust-lang/rust/issues/82171 (有个workaround,不知道为啥可行)

或者用#![feature(type_alias_impl_trait)]

type IterA<'a> = impl Iterator<Item=&'a u8>+'a;

fn foo<'a,A>(s:&'a u8,_a:A)-> IterA<'a> {
    std::iter::once(s)
}
Airtnp 2021-08-22 09:38

类似的issue https://github.com/rust-lang/rust/issues/79415 https://github.com/rust-lang/rust/issues/82171 (有个workaround,不知道为啥可行)

或者用#![feature(type_alias_impl_trait)]

type IterA<'a> = impl Iterator<Item=&'a u8>+'a;

fn foo<'a,A>(s:&'a u8,_a:A)-> IterA<'a> {
    std::iter::once(s)
}
作者 TsuITOAR 2021-08-22 00:57

应该是impl trait语法自身的一些限制,下面这个就可以编译

fn main(){
    let i:u8=1;
    let mut p;
    let r=&i;
    {
        let j=0;
        p=foo(r,&j);
    }
    println!("{:?}",p.next())
}

fn foo<'a,A>(s:&'a u8,_a:A)->std::iter::Once<&'a u8>{
    std::iter::once(s)
}

作为对比,下面这个可以编译

fn main(){
    let i:u8=1;
    let w;
    let r=&i;
    {
        let j=0;
        w=foo(r,&j);
    }
    println!("{}",w.as_ref())
}

fn foo<'a,A>(s:&'a u8,_a:A)->Wrapper<'a>{
    Wrapper(s)
}

struct Wrapper<'a>(&'a u8);

impl<'a> AsRef<u8> for Wrapper<'a>{
    fn as_ref(&self)->&u8{
        self.0
    }
}

但这个不行

fn main(){
    let i:u8=1;
    let w;
    let r=&i;
    {
        let j=0;
        w=foo(r,&j);
    }
    println!("{}",w.as_ref())
}
//把返回类型变成了impl trait模式
fn foo<'a,A>(s:&'a u8,_a:A)->impl AsRef<u8>+'a{
    Wrapper(s)
}

struct Wrapper<'a>(&'a u8);

impl<'a> AsRef<u8> for Wrapper<'a>{
    fn as_ref(&self)->&u8{
        self.0
    }
}
 Compiling playground v0.0.1 (/playground)
error[E0597]: `j` does not live long enough
 --> src/main.rs:7:17
  |
7 |         w=foo(r,&j);
  |                 ^^ borrowed value does not live long enough
8 |     }
  |     - `j` dropped here while still borrowed
9 |     println!("{}",w.as_ref())
  |                   - borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

playground

streetmask 2021-08-22 00:08

“lifetime is used to prevent creating a longer one from a shorter one.” 我比较认同这个

作者 TsuITOAR 2021-08-21 23:57

哦我的例子不太对,j的lifetime是'static的,下面这个例子就会报错

fn main(){
    let i:u8=1;
    let mut p;
    let r=&i;
    {
        let j=0;
        p=foo(r,&j);
    }
    println!("{:?}",p.next())
}

fn foo<'a,A>(s:&'a u8,_a:A)->impl Iterator<Item=&u8>+'a{
    std::iter::once(s)
}

那么也就是所有的传入参数生命周期都需要满足'a的bound,似乎不太合理,因为有一些参数实际并没有用到或者在函数返回后借用就结束了。这么设计是有什么特殊考虑吗

--
👇
streetmask: lifetime取最短的,像它说的那样给A加个限制就行了

作者 TsuITOAR 2021-08-21 23:51

但是我返回值的lifetime与A是无关的,正如我最后的可编译的例子里面,那里的A的lifetime短于'a,但是不影响我的编译通过

streetmask 2021-08-21 23:16

lifetime取最短的,像它说的那样给A加个限制就行了

1 共 7 条评论, 1 页