< 返回版块

leolee0101 发表于 2022-05-26 13:28

一个例子

    pub fn live_regions<'a>(
        &'a self,
        live_bits: BitSlice<'a>,   //@ BitSlice 是 内部有引用成员。 &'a [Word] 。
    ) -> impl Iterator<Item = repr::RegionName> + 'a {
        self.regions_set(live_bits).into_iter()
    }

这里两个参数用同样的lifetime标注,我的理解是,两者要有一个重叠的lifetime 'a . 而返回值 为什么要加上 lifetime bound 'a?

相关函数:

fn regions_set(&self, live_bits: BitSlice) -> BTreeSet<repr::RegionName> 

#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct RegionName {
    name: InternedString
}

==== 追加: 这是一个开源项目里的。 如果有兴趣,可以查看: https://github.com/nikomatsakis/borrowck/blob/master/nll/src/liveness.rs 76-81 行。

评论区

写评论
苦瓜小仔 2022-07-27 11:20

是的,它们是等价的:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dd40ee999c094278e9298d2de29b596a

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=229df986421ddc928c65fca884bfe0ec

针对实现了 Copy trait 的类型,如果你这么做,则无需标注:

fn foo_expanded(x: &u8) -> impl Future<Output = u8> {
    let x = *x;
    async move { x }
}

当然这与上面两种的含义不同:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cca1ead3febd60c175305f9790f558e8


生命周期标注是双向契约,弄清楚生命周期能做什么,不能做什么最重要。而不是将关注点放在有没有生命周期标注上。

--
👇
zhouyu00:

zhouyu00 2022-07-27 10:04

async book里面有个类似的问题 https://rust-lang.github.io/async-book/03_async_await/01_chapter.html

// This function:
async fn foo(x: &u8) -> u8 { *x }

// Is equivalent to this function:
fn foo_expanded<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
    async move { *x }
}

返回值也带有生命周期标注

苦瓜小仔 2022-05-26 20:42

是的,你提醒我了,返回值是非引用类型,所以无需标注。

然后我重新看了一下,你看的代码已经是 2017 年的,这里补充一下。

考虑具有类似签名的方法:

struct A;
struct B<'b>(&'b [i32]);

impl A {
    // fn iter<'a, 'b>(&'a self, b: B<'b>) -> impl Iterator<Item = i32> { self.inner(b).into_iter() }
    fn iter(&self, b: B) -> impl Iterator<Item = i32> { self.inner(b).into_iter() }

    fn iter_over_constrained<'a>(&'a self, b: B<'a>) -> impl Iterator<Item = i32> + 'a {
        self.inner(b).into_iter()
    }

    fn inner(&self, b: B) -> BTreeSet<i32> { b.0.iter().cloned().collect() }
    fn use_mut(&mut self) {}
}

iteriter_over_constrained 的区别说起来很复杂,但只要理解这个 playground 里的为什么不通过,就足够了。

iter_over_constrained 就是你这里的 live_regions,但并不建议使用这种形式的标注,它很严格,所以很容易让你遇到借用导致的编译问题。

作者 leolee0101 2022-05-26 17:17

上一条回复,没看完。粗看了一下,很用心的推理了一长段。是有不严谨的地方吗?个人觉得如果可以,保留下来,我们这些菜鸟看看推理思路,也能学到很多。

--
👇
苦瓜小仔: https://doc.rust-lang.org/stable/book/ch10-03-lifetime-syntax.html#lifetime-annotation-syntax

Lifetime annotations don’t change how long any of the references live. Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes.

标注生命周期,就是描述多个引用之间的生命周期关系,仅此而已。

你不能阻止其他人想要描述下面的生命周期关系:

    pub fn live_regions<'a, 'b>(
        &'a self,
        live_bits: BitSlice<'b>, 
    ) -> impl Iterator<Item = repr::RegionName> + 'b {
        ...
    }

所以 Rust 需要你显示标注出来 —— 在此处无省略规则。

Rust 的确可以计算函数内部实际的生命周期情况,但通常无法在多个引用下为你选择你需要什么样的生命周期关系。

总之,Rust 要你标注生命周期,是将引用之间的生命周期关系决定权交给你。

作者 leolee0101 2022-05-26 14:08

嗯,我明白你的意思。 疑惑的地方是,那个返回值好像和引用并没有关系。是有隐含的引用吗?

--
👇
苦瓜小仔: https://doc.rust-lang.org/stable/book/ch10-03-lifetime-syntax.html#lifetime-annotation-syntax

Lifetime annotations don’t change how long any of the references live. Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes.

标注生命周期,就是描述多个引用之间的生命周期关系,仅此而已。

你不能阻止其他人想要描述下面的生命周期关系:

    pub fn live_regions<'a, 'b>(
        &'a self,
        live_bits: BitSlice<'b>, 
    ) -> impl Iterator<Item = repr::RegionName> + 'b {
        ...
    }

所以 Rust 需要你显示标注出来 —— 在此处无省略规则。

Rust 的确可以计算函数内部实际的生命周期情况,但通常无法在多个引用下为你选择你需要什么样的生命周期关系。

总之,Rust 要你标注生命周期,是将引用之间的生命周期关系决定权交给你。

苦瓜小仔 2022-05-26 13:55

https://doc.rust-lang.org/stable/book/ch10-03-lifetime-syntax.html#lifetime-annotation-syntax

Lifetime annotations don’t change how long any of the references live. Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes.

标注生命周期,就是描述多个引用之间的生命周期关系,仅此而已。

你不能阻止其他人想要描述下面的生命周期关系:

    pub fn live_regions<'a, 'b>(
        &'a self,
        live_bits: BitSlice<'b>, 
    ) -> impl Iterator<Item = repr::RegionName> + 'b {
        ...
    }

所以 Rust 需要你显示标注出来 —— 在此处无省略规则。

Rust 的确可以计算函数内部实际的生命周期情况,但通常无法在多个引用下为你选择你需要什么样的生命周期关系。

总之,Rust 要你标注生命周期,是将引用之间的生命周期关系决定权交给你。

1 共 6 条评论, 1 页