Too-many-lists: 在 3.6 IterMut 中详细说明 iter.next() 中的生命周期

创建于 2016-08-19  ·  5评论  ·  资料来源: rust-unofficial/too-many-lists

next的签名在输入和输出的生命周期之间建立 _no_ 约束! 我们为什么要关心? 这意味着我们可以无条件地一遍又一遍地调用next

我觉得这里有逻辑上的差距。 IIUC 生命周期是为了限制输出相对于输入的范围,它如何阻止next()被连续调用并不直观。

的具体例子

fn next<'b>(&'b mut self) -> Option<&'a T> { /* stuff */ }

将直接导致Option<&'a T>T Option<&'a T>存在的时间一样长的结论,直到该元素被drop() ed 或整个列表都已死。 与Option<&'b T>的主要区别在于元素是drop() ed 时。

next()第二次(和第三次)被调用时会发生什么?

最有用的评论

也许我应该先重新发布我之前删除的帖子......这对你有帮助吗?

IIUC 生命周期旨在限制输出相对于输入的范围,...

这不是指定生命周期的唯一目的。 主要是将函数/方法调用或复杂类型中的 _borrows_ 与另一个相关联。 您将您的意图传达给编译器,因此它可以根据您的意图进行推理,并决定这些意图是否符合其安全规则。

在此处提供的脱糖示例中:

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next<'b>(&'b mut self) -> Option<&'a T> { /* stuff */ }
}

我们可以看到self的借用没有链接到返回的引用。 生命周期的命名不同,它们没有任何关系。

self的借用发生在我们调用next() ,但它不会通过将返回的引用存储在变量中来扩展,如下所示:

let x = iter.next().unwrap();

返回的引用具有生命周期'a而不是'b 。 因此, self的借用只持续到调用next()那一刻。 因此,我随后可以再次调用next() ,因为self的可变借用只持续了那一刻。

让我们假设它会持续更长时间,并且方法签名看起来像这样(注意,你不能用今天的 Rust 做到这一点,因为 Iterator trait 指定了上面的签名):

fn next<'a>(&'a mut self) -> Option<&'a T>;

现在我向编译器传达,我希望将两个生命周期/借用链接起来。 因此,如果我调用next()并将返回的引用/借用存储在一个变量中,那么只要该变量在范围内,就会将self的借用扩展到持续时间。 然后我不能这样做:

let x = iter.next().unwrap();
let y = iter.next().unwrap(); // error, more than one mutable borrow of iter!

到我第二次调用next()时, x仍在范围内,因此iter的可变借用(即self next() ) 的签名也在范围内。 你可以看到这将是非常有限的。 在我们可以继续调用next()之前, x必须超出范围。

这也是不必要的。 Iter借用了一个 T(或一些 T 的集合),它不拥有T,所以我不是从Iter (上面的第二个例子传达给编译器)借用的。 我向 T 借款。 Iter只是 T 的另一个借款人,我正在用它来获得 T 的另一个借款。在此过程中可变地借入Iter完全是矫枉过正。

作者@Gankro在这里所做的是设置舞台,以强调与IterMut的区别。 那个返回可变引用( &mut T )。 使用Iter可以获得对基础数据的多个共享引用。 这对于共享引用来说是微不足道的; 范围内可以有多个。 令人惊奇的是,这对于可变引用也是可能的,只要您从中借用的底层数据结构轻松分区为 _disjoint_ 子结构。

所有5条评论

您是在提问还是希望文章包含更多说明? 换句话说,您是不确定这里的意思,还是您已经知道并且只是想扩展这篇文章? 我不完全确定。 :微笑:

@jonastepe
两者都有。 我在 OP 中只能走这么远,无法从生命周期限制到函数调用限制。 我认为需要澄清,但我只知道其中的一部分。

也许我应该先重新发布我之前删除的帖子......这对你有帮助吗?

IIUC 生命周期旨在限制输出相对于输入的范围,...

这不是指定生命周期的唯一目的。 主要是将函数/方法调用或复杂类型中的 _borrows_ 与另一个相关联。 您将您的意图传达给编译器,因此它可以根据您的意图进行推理,并决定这些意图是否符合其安全规则。

在此处提供的脱糖示例中:

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next<'b>(&'b mut self) -> Option<&'a T> { /* stuff */ }
}

我们可以看到self的借用没有链接到返回的引用。 生命周期的命名不同,它们没有任何关系。

self的借用发生在我们调用next() ,但它不会通过将返回的引用存储在变量中来扩展,如下所示:

let x = iter.next().unwrap();

返回的引用具有生命周期'a而不是'b 。 因此, self的借用只持续到调用next()那一刻。 因此,我随后可以再次调用next() ,因为self的可变借用只持续了那一刻。

让我们假设它会持续更长时间,并且方法签名看起来像这样(注意,你不能用今天的 Rust 做到这一点,因为 Iterator trait 指定了上面的签名):

fn next<'a>(&'a mut self) -> Option<&'a T>;

现在我向编译器传达,我希望将两个生命周期/借用链接起来。 因此,如果我调用next()并将返回的引用/借用存储在一个变量中,那么只要该变量在范围内,就会将self的借用扩展到持续时间。 然后我不能这样做:

let x = iter.next().unwrap();
let y = iter.next().unwrap(); // error, more than one mutable borrow of iter!

到我第二次调用next()时, x仍在范围内,因此iter的可变借用(即self next() ) 的签名也在范围内。 你可以看到这将是非常有限的。 在我们可以继续调用next()之前, x必须超出范围。

这也是不必要的。 Iter借用了一个 T(或一些 T 的集合),它不拥有T,所以我不是从Iter (上面的第二个例子传达给编译器)借用的。 我向 T 借款。 Iter只是 T 的另一个借款人,我正在用它来获得 T 的另一个借款。在此过程中可变地借入Iter完全是矫枉过正。

作者@Gankro在这里所做的是设置舞台,以强调与IterMut的区别。 那个返回可变引用( &mut T )。 使用Iter可以获得对基础数据的多个共享引用。 这对于共享引用来说是微不足道的; 范围内可以有多个。 令人惊奇的是,这对于可变引用也是可能的,只要您从中借用的底层数据结构轻松分区为 _disjoint_ 子结构。

@jonastepe
非常感谢! 我怀疑赋值和&mut会共同阻止第二次函数调用,但未能将生命周期融入这个难题中。 我非常希望将您的解释添加到书中。 可以提交PR吗? 如果不是,我可以吗?

当然你可能:眨眼:。 我认为这本书目前需要更多的内容和解释。 Rust 中的数据结构因其所有权规则而成为一种特殊的话题。 我认为将来我们也应该为其他数据结构提供实现示例。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

kontrafiktion picture kontrafiktion  ·  9评论

ericye16 picture ericye16  ·  10评论

Gankra picture Gankra  ·  3评论

orionz picture orionz  ·  3评论

reem picture reem  ·  3评论