为了学习Rust,我开始研究一个简单的解析器.我得到了它的工作,但我使用了很多不好的做法,如使用.clone()来保存我的结构中的数据.
今天我开始重构代码以使用对象的引用而不是克隆它们.在陷入这两个错误之前我已经走了很远的路:
error: cannot borrow 'm_list' as mutable because it is also borrowed as immutable [E0502]
和
error: cannot borrow 'h_list' as mutable because it is also borrowed as immutable [E0502]
看完错误之后,我很困惑.有人说这是Rust的借阅检查器中的一个错误,但我99%肯定它是我的代码的错误.
错误表现的代码:
mod utypes;
use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::error::Error;
use utypes::*;
fn main() {
let args: Vec<_> = env::args().collect();
let file = match File::open(&args[1]) {
Ok(file) => file,
Err(why) => panic!("IO Error on line: {}, cause: {}", line!(), Error::description(&why)),
};
let buffer = BufReader::new(file);
let mut m_list: Vec<Materia> = Vec::new();
let mut h_list: Vec<Hora> = Vec::new();
let mut t_list: Vec<Turno> = Vec::new();
for line in buffer.lines() {
let l = line.unwrap();
let spl_line: Vec<&str> = l.split(':').collect();
if spl_line[0].starts_with('#') { continue; }
match spl_line[0] {
"mat" => { parse_mat(&mut m_list,spl_line) },
"hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
"trn" => { parse_trn(&mut t_list,spl_line) },
"tad" => { exec_tad(&h_list,&mut t_list,spl_line) },
"" => continue,
_ => panic!("Unknown type identifier: {}.", spl_line[0]),
}
}
for turno in t_list.iter() {
println!("\nTurno: {}:\n", turno.nombre);
for dia in turno.dias.iter() {
print!("{:?}: ", dia.enum_id);
for hora in dia.horas.iter() {
print!("\n\t{} ", hora);
}
println!("");
}
}
/*
println!("\nDEBUG INFO:\n");
println!("{:?}", m_list);
println!("{:?}", h_list);
println!("{:?}", t_list);
*/
}
fn get_trn( t_list: &Vec<Turno>, gid: u32 ) -> Option<usize> {
for (i,trn) in t_list.iter().enumerate() {
if trn.id == gid {
return Some(i);
}
}
None
}
fn get_hra ( h_list: &Vec<Hora>, gid: u32 ) -> Option<usize> {
for (i,hra) in h_list.iter().enumerate() {
if hra.id == gid {
return Some(i);
}
}
None
}
fn get_mat ( m_list: &Vec<Materia>, gid: u32 ) -> Option<usize> {
for (i,mat) in m_list.iter().enumerate() {
if mat.id == gid {
return Some(i);
}
}
None
}
fn parse_mat<'a> ( m_list: &'a mut Vec<Materia>, line: Vec<&str> ) {
assert_eq!(4,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
m_list.push(Materia::new(id,line[2].to_string(),line[3].to_string()));
}
fn parse_hra<'a> ( m_list: &'a Vec<Materia>, h_list: &mut Vec<Hora<'a>>, line: Vec<&str> ) {
assert_eq!(5,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let start: u32 = match line[2].parse::<u32>() {
Ok(start) => start,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let durat: u32 = match line[3].parse::<u32>() {
Ok(durat) => durat,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let matid: u32 = match line[4].parse::<u32>() {
Ok(matid) => matid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let mat_i: usize = match get_mat(m_list,matid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
h_list.push(Hora::new(id,start,durat,&m_list[mat_i]));
}
fn parse_trn<'a> ( t_list: &mut Vec<Turno<'a>>, line: Vec<&str> ) {
assert_eq!(3,line.len());
let id: u32 = match line[1].parse::<u32>() {
Ok(id) => id,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
t_list.push(Turno::new(id,line[2].to_string()));
}
fn exec_tad<'a> ( h_list: &'a Vec<Hora<'a>>, t_list: &mut Vec<Turno<'a>>, line: Vec<&str> ) {
assert_eq!(4,line.len());
let hid: u32 = match line[2].parse::<u32>(){
Ok(hid) => hid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let tid: u32 = match line[3].parse::<u32>(){
Ok(tid) => tid,
Err(_) => panic!("Error parsing u32 at {}.", line!()),
};
let hra_i: usize = match get_hra(h_list,hid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
let trn_i: usize = match get_trn(t_list,tid) {
Some(x) => x,
None => panic!("Error matid not found in m_list!")
};
match line[1] {
"Dom" => t_list[trn_i].addhra(Dias::Dom,&h_list[hra_i]),
"Lun" => t_list[trn_i].addhra(Dias::Lun,&h_list[hra_i]),
"Mar" => t_list[trn_i].addhra(Dias::Mar,&h_list[hra_i]),
"Mie" => t_list[trn_i].addhra(Dias::Mie,&h_list[hra_i]),
"Jue" => t_list[trn_i].addhra(Dias::Jue,&h_list[hra_i]),
"Vie" => t_list[trn_i].addhra(Dias::Vie,&h_list[hra_i]),
"Sab" => t_list[trn_i].addhra(Dias::Sab,&h_list[hra_i]),
_ => panic!("Unknown day error!")
}
}
和utypes.rs:
use std::fmt;
//Dias
#[derive(Debug)]
pub enum Dias {
Dom,
Lun,
Mar,
Mie,
Jue,
Vie,
Sab,
}
//Materia
#[derive(Debug)]
pub struct Materia {
pub id: u32,
pub nombre: String,
pub profesor: String,
}
impl Materia {
pub fn new( i: u32, nom: String, prof: String ) -> Materia {
Materia {
id: i,
nombre: nom,
profesor: prof,
}
}
}
//Hora
#[derive(Debug,Clone)]
pub struct Hora<'a> {
pub id: u32,
pub comienzo: u32,
pub duracion: u32,
pub materia: &'a Materia,
}
impl<'a> Hora<'a> {
pub fn new ( id: u32, com: u32, dur: u32, mat: &'a Materia ) -> Hora<'a> {
Hora {
id: id,
comienzo: com,
duracion: dur,
materia: mat,
}
}
pub fn fin ( &self ) -> u32 {
self.comienzo + self.duracion
}
pub fn fmt_time ( tot: u32 ) -> String {
let min = ( tot / 60 ) % 60;
let hra = tot / 3600;
format!("{:02}:{:02}", hra, min)
}
}
impl<'a> fmt::Display for Hora<'a> {
fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result {
write!(f, "[{}-{}, {}]", Hora::fmt_time(self.comienzo), Hora::fmt_time(self.fin()), self.materia.nombre)
}
}
//Dia
#[derive(Debug)]
pub struct Dia<'a> {
pub enum_id: Dias,
pub nombre: String,
pub horas: Vec<&'a Hora<'a>>,
}
impl<'a> Dia<'a> {
pub fn new( ei: Dias, nom: String ) -> Dia<'a> {
Dia {
enum_id: ei,
nombre: nom,
horas: Vec::new(),
}
}
pub fn addhra( &mut self, hra: &'a Hora<'a> ){
self.horas.push(hra);
}
}
//Turno
#[derive(Debug)]
pub struct Turno<'a> {
pub id: u32,
pub nombre: String,
pub dias: [Dia<'a>; 7],
}
impl<'a> Turno<'a> {
pub fn new( i: u32, nom: String ) -> Turno<'a> {
Turno {
id: i,
nombre: nom,
dias: [
Dia::new(Dias::Dom,"Domingo" .to_string()),
Dia::new(Dias::Lun,"Lunes" .to_string()),
Dia::new(Dias::Mar,"Martes" .to_string()),
Dia::new(Dias::Mie,"Miercoles".to_string()),
Dia::new(Dias::Jue,"Jueves" .to_string()),
Dia::new(Dias::Vie,"Viernes" .to_string()),
Dia::new(Dias::Sab,"Sabado" .to_string())
],
}
}
pub fn addhra( &mut self, dia: Dias, hra: &'a Hora<'a> ) {
match dia {
Dias::Dom => self.dias[0].addhra(hra),
Dias::Lun => self.dias[1].addhra(hra),
Dias::Mar => self.dias[2].addhra(hra),
Dias::Mie => self.dias[3].addhra(hra),
Dias::Jue => self.dias[4].addhra(hra),
Dias::Vie => self.dias[5].addhra(hra),
Dias::Sab => self.dias[6].addhra(hra),
}
}
}
我认为可变参考& mut m_list在函数parse_mat()返回后结束,所以我应该能够在for循环的另一次迭代中调用parse_hra()并传递& m_list而没有问题,对吗?
完整错误:
src/main.rs:36:39: 36:45 error: cannot borrow `m_list` as mutable because it is also borrowed as immutable [E0502]
src/main.rs:36 "mat" => { parse_mat(&mut m_list,spl_line) },
^~~~~~
src/main.rs:37:35: 37:41 note: previous borrow of `m_list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `m_list` until the borrow ends
src/main.rs:37 "hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
^~~~~~
src/main.rs:71:2: 71:2 note: previous borrow ends here
src/main.rs:11 fn main() {
...
src/main.rs:71 }
^
src/main.rs:37:47: 37:53 error: cannot borrow `h_list` as mutable because it is also borrowed as immutable [E0502]
src/main.rs:37 "hra" => { parse_hra(&m_list,&mut h_list,spl_line) },
^~~~~~
src/main.rs:39:34: 39:40 note: previous borrow of `h_list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `h_list` until the borrow ends
src/main.rs:39 "tad" => { exec_tad(&h_list,&mut t_list,spl_line) },
^~~~~~
src/main.rs:71:2: 71:2 note: previous borrow ends here
src/main.rs:11 fn main() {
...
src/main.rs:71 }
^
我不是母语人士,对任何错误都很抱歉.
最佳答案 @aSpex评论是对的.
要解决此问题,您可以使用相应的索引替换Hora和Dia内的引用.那是
struct Hora {
materia: usize; //index in m_list
}
struct Dia {
horas: Vec<usize>; //indices in h_list
}
您还可以使用字段m_list,h_list和t_list创建一个结构,以便它们保持在一起.
有关使用Rc和RefCell的方法的比较,请参见this.