【问题标题】:Cannot assign to `self.x` because it is borrowed无法分配给“self.x”,因为它是借来的
【发布时间】:2018-04-18 10:06:53
【问题描述】:

我有两个功能:

// A simple struct
struct S {
    w: u8,
    h: u8,
    x: Vec<u8>,
    y: Vec<u8>,
}

// Implementation of the struct S
impl S {
    // Seems to work
    fn new(_w: u8, _h: u8, _x: &Vec<u8>, _y: &Vec<u8>) -> S {
        S {
            w: _w,
            h: _h,
            x: _x.clone(),
            y: _y.clone(),
        }
    }

    fn calc(&mut self) {
        let mut min_x = self.x.iter().min().unwrap();
        let mut max_x = self.x.iter().max().unwrap();
        let mut min_y = self.y.iter().min().unwrap();
        let mut max_y = self.y.iter().max().unwrap();

        // Here's the line that gives the error
        self.x = self.x
            .iter()
            .map(|v| norm_value(*v, *min_x, *max_x, 0, self.w))
            .collect();
    }
}

fn norm_value<A, B, C, D, E>(_: A, _: B, _: C, _: D, _: E) -> ! { panic!() }
  1. new 创建一个新的 S 对象。这似乎有效,但如果我做错了什么并且恰好有效,请纠正我。

  2. calc 尝试修改成员xy

编译器报这个错误:

error[E0506]: cannot assign to `self.x` because it is borrowed
  --> src/main.rs:28:9
   |
22 |           let mut min_x = self.x.iter().min().unwrap();
   |                           ------ borrow of `self.x` occurs here
...
28 | /         self.x = self.x
29 | |             .iter()
30 | |             .map(|v| norm_value(*v, *min_x, *max_x, 0, self.w))
31 | |             .collect();
   | |______________________^ assignment to borrowed `self.x` occurs here

我在哪里借到self.x?我是 Rust 新手,但这样的事情毫无意义。

【问题讨论】:

    标签: rust ownership borrow-checker


    【解决方案1】:

    calc 开头的所有变量绑定都将共享引用 (&amp;u8) 返回到 self.xself.y,这意味着您不能再改变它们。

    为了在最后一次赋值时不受这些借用的约束,您可以通过clone() 引用来获得常规的u8s:

    let mut min_x = self.x.iter().min().unwrap().clone();
    let mut max_x = self.x.iter().max().unwrap().clone();
    let mut min_y = self.y.iter().min().unwrap().clone();
    let mut max_y = self.y.iter().max().unwrap().clone();
    

    我不确定这是否能解决您的所有问题,因为您没有提供norm_value 的签名。

    至于new 方法,您可能希望更改签名以通过值而不是通过引用来获取它们:

    fn new(w: u8, h: u8, x: Vec<u8>, y: Vec<u8>) -> S {
        S { w: w, h: h, x: x, y: y }
    }
    
    let s = S::new(10, 10, vec![1, 2, 3, 4], vec![52, 10, 23, 56]);
    

    请注意,我删除了下划线 - 您不需要在函数参数前面加上它们,如果您删除它们,编译器仍然会清楚。在变量标识符前加下划线通常用于消除#[warn(unused_variables)] 警告。

    【讨论】:

    • 确实,这行得通。所以,如果我做对了:min().unwrap() 返回一个对self.x 元素的引用,这意味着整个self.x 被借用(或者只是一个单独的元素?(分钟))。最后clone()复制引用的值并释放引用?
    • @DimChtz iter() 在不可变引用上返回一个迭代器,它借用整个 self.xself.y(但不是整个 self)。min().unwrap() 返回对最小元素的引用;它消耗迭代器,但保持借用有效。 clone()获取引用的值并释放借用,是的。
    • 这样的事情让我觉得 rust 搞砸了,但我还是喜欢 rust :P 无论如何,谢谢。
    • 最后一个问题:考虑到new 签名,这:let mut s = S::new(10, 10, &amp;vec![1,2,3,4], &amp;vec![52, 10, 23, 56]); 是调用new 的正确方法还是会导致任何内存问题?
    • @DimChtz 不,这不会引起问题,但是通过值而不是通过引用获取 _x_y 向量会更有意义 - 这样您就不需要分配他们的内存两次,就像在这个调用中一样。 Rust 最好的特性之一是,如果编译器允许某些东西,那么它应该是完全安全的(当然,除非你使用 unsafe)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-08
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    相关资源
    最近更新 更多