gpt4 book ai didi

return - 为什么提早归还未完成未偿还的借贷?

转载 作者:行者123 更新时间:2023-11-29 07:56:43 25 4
gpt4 key购买 nike

我正在尝试编写一个函数,仅当元素大于向量中已有的最后一个元素时才将元素插入排序向量的末尾,否则返回错误并返回最大元素的引用。据我所知,这似乎没有违反任何借贷规则,但借贷检查员不喜欢它。我不明白为什么。

struct MyArray<K, V>(Vec<(K, V)>);

impl<K: Ord, V> MyArray<K, V> {
pub fn insert_largest(&mut self, k: K, v: V) -> Result<(), &K> {
{
match self.0.iter().next_back() {
None => (),
Some(&(ref lk, _)) => {
if lk > &k {
return Err(lk);
}
}
};
}
self.0.push((k, v));
Ok(())
}
}

error[E0502]: cannot borrow `self.0` as mutable because it is also borrowed as immutable
--> src/main.rs:15:9
|
6 | match self.0.iter().next_back() {
| ------ immutable borrow occurs here
...
15 | self.0.push((k, v));
| ^^^^^^ mutable borrow occurs here
16 | Ok(())
17 | }
| - immutable borrow ends here

为什么这行不通?


回应Paolo Falabella's answer .

我们可以将任何带有 return 语句的函数转换为没有 return 语句的函数,如下所示:

fn my_func() -> &MyType {
'inner: {
// Do some stuff
return &x;
}
// And some more stuff
}

进入

fn my_func() -> &MyType {
let res;
'outer: {
'inner: {
// Do some stuff
res = &x;
break 'outer;
}
// And some more stuff
}
res
}

由此可见,借用超出了'inner的范围。

为了借用检查的目的而不是使用以下重写有什么问题吗?

fn my_func() -> &MyType {
'outer: {
'inner: {
// Do some stuff
break 'outer;
}
// And some more stuff
}
panic!()
}

考虑到 return 语句可以防止之后发生任何可能违反借用规则的事情。

最佳答案

如果我们明确命名生命周期,insert_largest 的签名变成 fn insert_largest<'a>(&'a mut self, k: K, v: V) -> Result<(), &'a K> .因此,当您创建返回类型时 &K , 它的生命周期将与 &mut self 相同.

而且,事实上,您正在返回 lk从里面self .编译器看到对 lk 的引用逃脱匹配的范围(因为它被分配给函数的返回值,所以它必须比函数本身长寿)并且它不能在匹配结束时让借用结束。

我想你是说编译器应该更聪明并意识到 self.0.push只有在 lk 时才能到达没有被退回。但事实并非如此。而且我什至不确定教它进行这种分析会有多困难,因为它比我今天理解借用检查器原因的方式要复杂一些。

今天,编译器看到一个引用并基本上尝试回答一个问题(“它能活多久?”)。当它看到你的返回值为lk时, 它分配 lk它期望从 fn 的签名返回值的生命周期('a 具有我们在上面给它的显式名称)并称之为一天。

所以,简而言之:

  • 是否应该提前返回结束对自身的可变借用?不。如前所述,借用应该扩展到函数之外并遵循其返回值
  • 在从早期返回到函数结束的代码中,借用检查器是否有点过于严格?是的,我认为是这样。提前返回之后和函数结束之前的部分只有在函数没有提前返回的情况下才能到达,所以我认为你的观点是,在那个特定的代码区域中,对借用检查的借用可能不太严格
  • 我认为更改编译器以启用该模式是否可行/可取?我不知道。借用检查器是 Rust 编译器中最复杂的部分之一,我没有资格给你一个答案。这似乎与关于 non-lexical borrow scopes 的讨论有关(甚至可能是其中的一部分) ,所以我鼓励您研究它,如果您对此主题感兴趣,可以做出贡献。

目前,如果可能的话,我建议只返回一个克隆而不是一个引用。我假设返回一个 Err不是典型情况,所以性能不应该特别担心,但我不确定 K:Clone 是怎样的bound 可能适用于您正在使用的类型。

impl <K, V> MyArray<K, V> where K:Clone + Ord { // 1. now K is also Clone
pub fn insert_largest(&mut self, k: K, v: V) ->
Result<(), K> { // 2. returning K (not &K)
match self.0.iter().next_back() {
None => (),
Some(&(ref lk, _)) => {
if lk > &k {
return Err(lk.clone()); // 3. returning a clone
}
}
};
self.0.push((k, v));
Ok(())
}
}

关于return - 为什么提早归还未完成未偿还的借贷?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34845546/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com