Rust 无法移出可变引用后面的***

Rust 无法移出可变引用后面的***,rust,Rust,我有下一个代码: struct Tokenizer { reader: BufReader<File>, buf: Vec<u8>, token: String } impl Tokenizer { fn new(path: &PathBuf) -> Tokenizer { let file = File::open(path).expect("Unable to open file!")

我有下一个代码:

struct Tokenizer {
    reader: BufReader<File>,
    buf: Vec<u8>,
    token: String
}

impl Tokenizer {
    fn new(path: &PathBuf) -> Tokenizer {
        let file = File::open(path).expect("Unable to open file!");
        Tokenizer {
            reader: BufReader::new(file),
            buf: Vec::<u8>::new(),
            token: String::new()
        }
    }

    fn next(&mut self) -> bool {
        if self.buf.len() == 0 {
            if self.reader.read_until(b'\n', &mut self.buf)
                .expect("Unable to read file") == 0 {
                return false;
            }
        }
        let s = String::from_utf8(self.buf).expect("Unable to read file");
        let mut start: i8 = -1;
        let mut end: i8 = -1;
        for (i, c) in s.char_indices() {
            if start == -1 {
                if !c.is_whitespace() {
                    start = i as i8;
                }
            } else {
                if c.is_whitespace() {
                    end = i as i8;
                }
            }
        }
        self.token = s.chars().skip(start as usize).take((end - start) as usize).collect();
        self.buf = s.into_bytes();
        self.buf.clear();
        return true;
    }
}
struct标记器{
读者:BufReader,
buf:Vec,
令牌:字符串
}
impl标记器{
fn新建(路径:&PathBuf)->标记器{
让file=file::open(path).expect(“无法打开文件!”);
标记器{
读卡器:BufReader::new(文件),
buf:Vec:::new(),
令牌:String::new()
}
}
fn下一步(&mut self)->bool{
如果self.buf.len()=0{
if self.reader.read_直到(b'\n',&mut self.buf)
.expect(“无法读取文件”)==0{
返回false;
}
}
让s=String::from_utf8(self.buf).expect(“无法读取文件”);
让mut开始:i8=-1;
让mut结束:i8=-1;
对于s.char_索引()中的(i,c){
如果开始==-1{
if!c.是_空格(){
开始=i为i8;
}
}否则{
如果c.is_whitespace(){
end=i为i8;
}
}
}
self.token=s.chars();
self.buf=s.到_字节();
self.buf.clear();
返回true;
}
}
但由于错误,它无法工作:

error[E0507]: cannot move out of `self.buf` which is behind a mutable reference
  --> src\parser.rs:28:35
   |
28 |         let s = String::from_utf8(self.buf).expect("Unable to read file");
   |                                   ^^^^^^^^ move occurs because `self.buf` has type `std::vec::Vec<u8>`, which does not implement the `Copy` trait
error[E0507]:无法移出可变引用后面的'self.buf'
-->src\parser.rs:28:35
|
28 | let s=String::from_utf8(self.buf).expect(“无法读取文件”);
|^^^^^^^^发生移动是因为'self.buf'的类型为'std::vec::vec',该类型未实现'Copy'特性

我读过类似的问题,建议使用
swap
,但我不知道这对我有什么帮助。如何修复此错误以及它为什么不编译?

您得到此错误的原因是
String::from\u utf8
试图获得其参数的所有权。在您的例子中,它是
&mut self
的属性,它被引用(您计划将来使用这个结构,而不是使用它)

简单的解决方法是使用其他参考功能:

fn next(&mut self)->bool{
...
设s=String::from_utf8_lossy(&self.buf[…]);
...
}

并将self.buf=s.删除为_字节()行,因为你是1。在下一行清洗;2.它没有被使用,而是被引用。

String::from_utf8
按值获取其参数,这意味着它不只是使用给定的向量,而是使用它

但是在这里它不能使用输入:因为
self
只是一个可变借用
self。buf
最多是一个可变借用(aka
&mut-Vec
),因此签名不匹配。这是因为
String::from_utf8
将检查输入是否有效,然后将其重新解释为有效字符串,以避免新的分配

有两种简单的方法可以解决这个问题:

最简单的方法是使用一个函数,该函数以引用作为输入,这将在内部分配一个新字符串以返回数据,因此效率稍低,但更方便

另一种选择——以及您得到的
swap
建议——是将数据移出借用:如果您有一个可变借用,您不能使用
self.buf
,但可以用一个新的(拥有的)缓冲区替换它

swap
执行此操作并返回旧值,因此您可以将
self.buf
的当前内容交换为全新(空)向量,并取出以前称为
self.buf
的向量,该向量现在归您所有(而不是
self
),因此是可消费的

这里看起来是这样的:

让mut buf=Vec::new();
交换(&mut buf,self.buf);
//现在我们使用交换的buf
让s=String::from_utf8(buf).expect(“无法读取文件”);
让mut开始:i8=-1;
让mut结束:i8=-1;
对于s.char_索引()中的(i,c){
如果开始==-1{
if!c.是_空格(){
开始=i为i8;
}
}否则{
如果c.is_whitespace(){
end=i为i8;
}
}
}
self.token=s.chars();
self.buf=s.到_字节();
self.buf.clear();
返回true;

在这种情况下,我认为
str::from_utf8
更合适。@rodrigo这是一个非消费函数的例子;)谢谢你的回答,我会尽量使用你的变体而不应对。