closure requires unique access

眉间皱痕 提交于 2019-12-22 09:58:13

问题


I'm trying to avoid repeating myself by using a closure in the following code:

fn add_raw(&mut self, pair: RawLinkPair) {
    let convert = |raw: &RawLink| {
        Link{
            id:         self.get_or_create(raw.name).id,
            flow:       raw.flow,
        }
    };

    println!("Hive received pair: {}", pair);
    let parent = convert(&pair.parent);
    let child = convert(&pair.child);
    self.link_concepts(parent, child);
}

That doesn't work. It gives me this error:

hive.rs:64:9: 64:13 error: cannot borrow `*self` as mutable because previous closure requires unique access
hive.rs:64         self.link_concepts(parent, child);
                   ^~~~
hive.rs:55:23: 60:10 note: previous borrow of `self` occurs here due to use in closure; the unique capture prevents subsequent moves or borrows of `self` until the borrow ends
hive.rs:55         let convert = |raw: RawLink| {
hive.rs:56             Link{
hive.rs:57                 id:         self.get_or_create(raw.name).id,
hive.rs:58                 flow:       raw.flow,
hive.rs:59             }
hive.rs:60         };
hive.rs:65:6: 65:6 note: previous borrow ends here
hive.rs:54     fn add_raw(&mut self, pair: RawLinkPair) {
...
hive.rs:65     }
               ^
error: aborting due to previous error

In this case I'm not actually saving myself too many keystrokes. I can type everything out by hand and it works fine:

fn add_raw(&mut self, pair: RawLinkPair) {
    let parent = Link {
        id:     self.get_or_create(pair.parent.name).id,
        flow:   pair.parent.flow,
    };

    let child = Link {
        id:     self.get_or_create(pair.child.name).id,
        flow:   pair.child.flow,
    };

    self.link_concepts(parent, child);
}

I understand the error (so I think), but:

  1. Is there something wrong with using a closure here in principal or did I just write this wrong?
  2. Is there a more idiomatic way to write this, or at least, how do I satisfy the borrow checker?
  3. This might be a dim question, but why doesn't the borrow just end immediately after the last time convert is called? It seems strange to me especially when I compare it to the bottom version, which ultimately does the same steps minus the closure.

回答1:


You should be able to fix it like this (something you called "satisfy the borrow checker"):

fn add_raw(&mut self, pair: RawLinkPair) {
    let (parent, child) = {
        let convert = |raw: RawLink| {
            Link{
                id:         self.get_or_create(raw.name).id,
                flow:       raw.flow,
            }
        };

        (convert(pair.parent.clone()), convert(pair.child.clone()))
    };
    self.link_concepts(parent, child);
}

As far as I know, this is something inexpressible in current Rust directly (i.e. without closures). Closures take their environment through &only reference (currently it is only available to compiler), which forbids taking other references until it goes out of scope. It is like &mut reference but not necessarily tied to mutability. Closure environment capture happens upon its creation, so lifetime of this capture extends to the end of the function, hence you're getting the error.

Why closures should take their environment by unique reference I don't know, though.



来源:https://stackoverflow.com/questions/23624381/closure-requires-unique-access

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!