Rust 就地更新锈蚀枚举很麻烦

Rust 就地更新锈蚀枚举很麻烦,rust,borrow-checker,Rust,Borrow Checker,我有两个案例枚举: #[derive(Debug)] pub enum Enum { Str(String), Fields { len: u32, opt: Option<String> }, } use Enum::*; 在某些情况下,我想切换枚举类型: pub fn update(x: &mut Enum) { match x { &mut Str(ref mut s) => { s.push('k'); }

我有两个案例枚举:

#[derive(Debug)]
pub enum Enum {
    Str(String),
    Fields { len: u32, opt: Option<String> },
}

use Enum::*;
在某些情况下,我想切换枚举类型:

pub fn update(x: &mut Enum) {
    match x {
        &mut Str(ref mut s) => { s.push('k'); }
        &mut Fields { ref mut len, ref mut opt } => { 
            if *len < 5 {
                *x = Str(String::from("default"));
            } else {
                *len += 1;
            }
        }
    }
}
现在我们遇到了更严重的麻烦:

错误[E0507]:无法移出借用的内容
-->src/main.rs:16:62
|
16 |&mut Some(ref s)=>{update_hack=Some(Str(*s))},
|^^无法移出借用的内容
这次我不知道如何解决这个问题。这感觉就像我们在堆积黑客,而应该有一个干净的方式。惯用的解决方案是什么


从Rust 1.23.0开始,借词总是词汇化的。从此匹配块创建的对
x
的可变引用:

match x {
    &mut Str(ref mut s) => { s.push('k'); }
    &mut Fields { ref mut len, ref mut opt } => { 
        if *len < 5 {
            *x = Str(String::from("default"));
        } else {
            *len += 1;
        }
    }
}
这个技巧之所以有效,是因为它限制了词法范围。你能行

pub fn update(x: &mut Enum) {
    let s = match *x {
        Str(ref mut s) => {
            s.push('k');
            return;
        }
        Fields {
            ref mut len,
            ref opt,
        } if *len >= 5 || opt.is_none() =>
        {
            *len += 1;
            return;
        }
        // opt is Some(str)
        // Option.take() is used to get String out of
        // &mut Option<String>
        Fields {
            len: _,
            ref mut opt,
        } => opt.take().unwrap(),
    };

    *x = Str(s);
}

从Rust 1.23.0开始,借词总是词汇化的。从此匹配块创建的对
x
的可变引用:

match x {
    &mut Str(ref mut s) => { s.push('k'); }
    &mut Fields { ref mut len, ref mut opt } => { 
        if *len < 5 {
            *x = Str(String::from("default"));
        } else {
            *len += 1;
        }
    }
}
这个技巧之所以有效,是因为它限制了词法范围。你能行

pub fn update(x: &mut Enum) {
    let s = match *x {
        Str(ref mut s) => {
            s.push('k');
            return;
        }
        Fields {
            ref mut len,
            ref opt,
        } if *len >= 5 || opt.is_none() =>
        {
            *len += 1;
            return;
        }
        // opt is Some(str)
        // Option.take() is used to get String out of
        // &mut Option<String>
        Fields {
            len: _,
            ref mut opt,
        } => opt.take().unwrap(),
    };

    *x = Str(s);
}

你的情况是不是可以使用一名比赛后卫?那是个好主意。我的实际代码有几个分支,其中一些分支使用子字段,因此它不容易用于该解决方案。也许有可能。你的情况是不是需要一个赛道后卫?那是个好主意。我的实际代码有几个分支,其中一些分支使用子字段,因此它不容易用于该解决方案。也许有可能。如果你认为这是一个独特的答案,我鼓励你把这个答案移到重复的答案上。你也可以。在夜晚的世界里,我为它感到兴奋,这让它更干净!我该怎么做?我不认为这是独一无二的。似乎有一个关于重复答案的规则吗?如果你认为这是一个独特的答案,我鼓励你把这个答案移到重复答案上。你也可以。在夜晚的世界里,我为它感到兴奋,这让它更干净!我该怎么做?我不认为这是独一无二的。似乎有重复答案的规则吗?
let mut x = String::from("a");
{
    let y = &mut x;
    *y = String::from("b");
}
// & to be explicit
println!("borrows x: {}", &x);
pub fn update(x: &mut Enum) {
    let s = match *x {
        Str(ref mut s) => {
            s.push('k');
            return;
        }
        Fields {
            ref mut len,
            ref opt,
        } if *len >= 5 || opt.is_none() =>
        {
            *len += 1;
            return;
        }
        // opt is Some(str)
        // Option.take() is used to get String out of
        // &mut Option<String>
        Fields {
            len: _,
            ref mut opt,
        } => opt.take().unwrap(),
    };

    *x = Str(s);
}
match *x {
    Str(ref mut s) => {
        s.push('k');
    }
    Fields {
        ref mut len,
        ref mut opt,
    } => {
        if *len < 5 {
            // Use Option::take() if you want to move owned value
            // out of &mut Option<String>
            match opt.take() {
                Some(s) => *x = Str(s),
                None => *len += 1,
            }
        } else {
            *len += 1;
        }
    }
}