如何在Rust中更改向量中的元素字段?

时间:2017-04-21 19:32:35

标签: rust

我有一个vec的某种结构类型,我想改变向量中第一个元素的某个字段。我怎么能这样做?

示例:

struct SomeType {
    some_value: i32,
}

fn main() {
    let mut vec = Vec::new();
    let mut t = SomeType { some_value: 45 };
    vec.push(t);

    println!("Old value: {}", vec.first().unwrap().some_value);
    vec.first().unwrap().some_value += 1;
    println!("New value: {}", vec.first().unwrap().some_value);
}

无法编译:

error: cannot assign to immutable field
  --> vec.rs:15:2
   |
15 |    vec.first().unwrap().some_value += 1;
   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field

我无法理解Rust中的可变性内容;这里有什么正确的方法?

5 个答案:

答案 0 :(得分:5)

要改变向量的第一个元素,通常会获得对该元素的引用。换句话说,引用向量。作为一个普通的结构,向量需要有一个方法可以为你提供参考。

事实是,对向量的引用意味着你可以对向量的内部做一些事情,读取它们或以某种方式修改它们。 Rust不知道细节,它只知道当你持有那个引用时,你可以做些什么。

只有那些有限的信息,Rust的借用检查器试图阻止你在脚下射击自己。它说:如果你要读取矢量,那么你可以按照你想要的任何方式读取它,你甚至可以读一些其他函数,或者两个函数,或者五个。但是你在阅读它时不能修改矢量,它不安全,它会导致错误。因此,您可以根据需要在向量中包含尽可能多的只读引用,但仅限于当您没有持有任何可写引用时。如果你确实持有可写参考,那么一次只能有一个这样的参考。

因此这种参考很重要。这就是为什么向量有两个方法可以为你提供第一个元素:firstfirst_mut

所以这里

let mut vec = Vec::new();

你的载体已经变异了。来自其他语言的你可能会从直觉中发挥作用,即如果向量是可变的一次,它总是可变的。有点像C ++中的const值或D中的immutable。它可能是可变的,也可能不是。

但是在Rust中,您可能希望将不可变引用转换为可变结构。例如,您可能希望一个线程处理向量的一个元素而另一个元素处理另一个元素,如果您宁愿保持借用检查器的安全带,那么获得多个引用的最简单方法是使它们保持不变。这就是为什么类似first的方法返回不可变引用并获得可变引用的原因,您需要使用不同的方法明确选择。

P.S。那有什么帮助吗?

答案 1 :(得分:3)

以下是同样有效的代码示例:

vec[0].some_value += 1;

vec.first_mut().unwrap().some_value += 1;

显示的代码问题是first()返回对第一个元素的(不可变)引用,但需要可变引用。

索引([0])的工作原理如下:

  1. vec derefs to slice
  2. 对来自index_mut trait
  3. 的切片调用IndexMut方法进行索引
  4. index_mut方法返回可变引用(&mut someType

答案 2 :(得分:1)

我认为您在参考时正在寻找&mut

#[derive(Debug)]
struct Character{
    name: String,
}

fn main() {
    let mut hobbits = vec![
        Character{name:String::from("Sam")},
        Character{name:String::from("Merry")},
        Character{name:String::from("Pepper")},
    ];

    {
        let third = &mut hobbits[2];
        third.name = String::from("Pippin");
    }

    println!("{:?}", hobbits);
}

注意{}围绕可变元素引用。需要限制可变参考范围。无法同时拥有可变且不可变的引用:println!third仍在范围内时会失败。

答案 3 :(得分:0)

这是一个古老的问题。我最近从Rust开始,我想尝试回答。

要更新第一个元素,我会这样做:

let mut st = &mut vec[0];
st.some_value += 1;

或者只是:

vec[0].some_value += 1;

要完全替换第一个元素,我可以这样做:

std::mem::replace(&mut vec[0], SomeType { some_value: 111 });

答案 4 :(得分:0)

您也可以通过这种方式执行此操作:

fn changeValues(mut list: Vec<i32>){
        println!("Before value change: {:?}", list.get(0).unwrap());
        list[0] = 3;
        println!("After value change: {:?}", list.get(0).unwrap());
    }