在迭代另一个不可变字段的同时改变一个字段 [英] Mutating one field while iterating over another immutable field

查看:23
本文介绍了在迭代另一个不可变字段的同时改变一个字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定以下程序:

struct Data {
    pub items: Vec<&'static str>,
}

trait Generator {
    fn append(&mut self, s: &str) {
        self.output().push_str(s);
    }

    fn data(&self) -> &Data;

    fn generate_items(&mut self) {
        for item in self.data().items.iter() {
            match *item {
                "foo" => self.append("it was foo
"),
                _ => self.append("it was something else
"),
            }
        }
    }

    fn output(&mut self) -> &mut String;
}

struct MyGenerator<'a> {
    data: &'a Data,
    output: String,
}

impl<'a> MyGenerator<'a> {
    fn generate(mut self) -> String {
        self.generate_items();

        self.output
    }
}

impl<'a> Generator for MyGenerator<'a> {
    fn data(&self) -> &Data {
        self.data
    }

    fn output(&mut self) -> &mut String {
        &mut self.output
    }
}

fn main() {
    let data = Data {
        items: vec!["foo", "bar", "baz"],
    };

    let generator = MyGenerator {
        data: &data,
        output: String::new(),
    };

    let output = generator.generate();

    println!("{}", output);
}

尝试编译它会产生以下错误:

The following errors are produced trying to compile it:

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:15:26
   |
13 |         for item in self.data().items.iter() {
   |                     ----                   - immutable borrow ends here
   |                     |
   |                     immutable borrow occurs here
14 |             match *item {
15 |                 "foo" => self.append("it was foo
"),
   |                          ^^^^ mutable borrow occurs here

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:16:22
   |
13 |         for item in self.data().items.iter() {
   |                     ----                   - immutable borrow ends here
   |                     |
   |                     immutable borrow occurs here
...
16 |                 _ => self.append("it was something else
"),
   |                      ^^^^ mutable borrow occurs here

构建代码以便在迭代不可变字段 data 时可以写入可变字段 output 的正确方法是什么?假设通过 Generator trait 的间接性被用来与其他结构共享类似的逻辑,所以从 trait 的默认方法实现中访问 MyStruct 的字段需要通过访问器来完成像这样的方法.

What is the proper way to structure the code so that the mutable field output can be written to while iterating over the immutable field data? Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.

推荐答案

假设通过 Generator trait 的间接性被用于与其他结构共享类似的逻辑,因此需要从 trait 的默认方法实现访问 MyStruct 的字段通过像这样的访问器方法完成.

Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.

那就不可能了.

当编译器直接看到这些字段时,它会识别对不同字段的访问;它不会打破抽象边界来窥视被调用的函数.

The compiler recognizes access to different fields when it sees such fields directly; it does not break abstraction boundaries to peek inside the functions called.

已经讨论了在方法上添加属性以具体提及哪个字段被哪个方法访问:

There have been discussions about adding attributes on the methods to specifically mention which field is accessed by which method:

  • 编译器会强制方法不涉及属性中未提及的任何字段
  • 然后编译器可以使用该方法仅对字段的子集进行操作的知识

然而……这是针对非虚拟方法的.

however... this is for non-virtual methods.

对于 trait 这会变得更加复杂,因为 trait 没有字段,而且每个实现者可能有一组不同的字段!

For a trait this gets significantly more complicated because a trait does not have fields, and each implementer may have a different set of fields!

那现在怎么办?

您需要更改代码:

  • 您可以将特征一分为二,并且需要两个对象(一个用于迭代,一个用于变异)
  • 您可以隐藏"append 方法的可变性,强制用户使用内部可变性
  • ...
  • you can split the trait in two, and require two objects (one to iterate, one to mutate)
  • you can "hide" the mutability of the append method, forcing users to use interior mutability
  • ...

这篇关于在迭代另一个不可变字段的同时改变一个字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆