In order to get to know Rust a bit better, I am building a simple text editor and have the following structs:
struct File {
rows: Vec<Row>,
filename: Option<String>
}
impl File {
fn row(&self, index: u16) -> &Row{
&self.rows[index as usize]
}
}
struct Row {
string: String,
}
struct EditorState {
file: File,
}
As you can see, I am keeping the state of an editor in a struct, which references the file, which contains a number of rows, which contains a string (Each of these structs has more fields, but I have removed the ones not relevant to the problem)
Now I want to make my rows editable and added this:
impl Row {
fn insert(&mut self, at: u16, c: char) {
let at = at as usize;
if at >= self.string.len() {
self.string.push(c);
} else {
self.string.insert(at, c)
}
}
}
This is how I try to update the row:
//In the actual functon, I am capturing the keypress,
//get the correct row from the state and pass it and the pressed
// char to row.insert
fn update_row(mut state: &mut EditorState) {
let row = &state.file.row(0);
row.insert(0, 'a');
}
This fails to compile:
error[E0596]: cannot borrow `*row` as mutable, as it is behind a `&` reference
From the error, I can see that the issue is that Row should be mutable so I can edit it (which makes sense, since I am mutating it's String). I can't figure out a) how to be able to mutate the string here, and b) how to do this without having row
always return a mutable reference, as in all other cases, I am calling row
to read a row, and not to write it.
First, we change s to be mut . Then we create a mutable reference with &mut s where we call the change function, and update the function signature to accept a mutable reference with some_string: &mut String . This makes it very clear that the change function will mutate the value it borrows.
A mutable type is a type whose instance data can be modified. The System. Text. StringBuilder class is an example of a mutable reference type. It contains members that can change the value of an instance of the class.
What is Borrowing? When a function transfers its control over a variable/value to another function temporarily, for a while, it is called borrowing. This is achieved by passing a reference to the variable (& var_name) rather than passing the variable/value itself to the function.
A reference represents a borrow of some owned value. You can get one by using the & or &mut operators on a value, or by using a ref or ref mut pattern. For those familiar with pointers, a reference is just a pointer that is assumed to not be null.
Here is a more idiomatic implementation for File
:
impl File {
fn row(&self, index: usize) -> Option<&Row> {
self.rows.get(index)
}
fn row_mut(&mut self, index: usize) -> Option<&mut Row> {
self.rows.get_mut(index)
}
}
Items of note here:
index
is out of bounds. The idiomatic way of handling this is to return an Option, which get
and get_mut
allow you to get for free.u16
is arbitrary here unless you really want to provide hard-coded limitations. In that case, I wouldn't rely on the type's max value but a constant instead that would make the intent clearer.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With