Why does Option<i32> lose mutability inside matched pattern? - rust

I'd like to change my_id, only if present, to another value:
fn read(id: &mut i32) {
*id = 42;
}
struct S {
my_id: Option<i32>,
}
impl S {
fn run(&mut self) {
match self.my_id {
Some(mut id) => read(&mut id),
_ => (),
}
}
}
fn main() {
let mut s = S { my_id: 0.into() };
s.run();
println!("{:?}", s.my_id);
}
playground
This code prints Some(0), which means the substitution failed, but I don't understand why. Am I losing the mutability because of pattern matching?

Shepmaster's answer and mcarton's answer gave great explanations how your i32 is being copied instead of referenced in the pattern match.
I'd like to add that the ref keyword exists specifically to handle cases like this, where you want a reference and not a copy inside a pattern match:
fn read(id: &mut i32) {
*id = 42;
}
struct S {
my_id: Option<i32>,
}
impl S {
fn run(&mut self) {
match self.my_id {
// `ref` keyword added here
Some(ref mut id) => read(id),
_ => (),
}
}
}
fn main() {
let mut s = S { my_id: 0.into() };
s.run();
println!("{:?}", s.my_id); // prints "Some(42)"
}
playground
See also:
Was Rust's ref keyword avoidable?
How can the ref keyword be avoided when pattern matching in a function taking &self or &mut self?
Why is `ref` used instead of an asterisk in pattern matching?

The problem becomes obvious when you replace the type of my_id by a non-Copy type:
fn read(_: &mut String) {}
struct S {
my_id: Option<String>,
}
impl S {
fn run(&mut self) {
match self.my_id {
Some(mut id) => read(&mut id),
_ => (),
}
}
}
error[E0507]: cannot move out of `self.my_id.0` which is behind a mutable reference
--> src/lib.rs:9:15
|
9 | match self.my_id {
| ^^^^^^^^^^ help: consider borrowing here: `&self.my_id`
10 | Some(mut id) => read(&mut id),
| ------
| |
| data moved here
| move occurs because `id` has type `std::string::String`, which does not implement the `Copy` trait
Indeed Some(mut id) does not match by reference: You've just made a copy of the field. What you really wanted was to match on &mut self.my_id, which doesn't require mut in the pattern:
match &mut self.my_id {
Some(id) => read(id),
_ => (),
}

Yes and no. By using Some(mut id), you are stating that id should be an i32. Because i32 implements Copy, a mutable copy of the value stored in self is made, then modified by read. At no point is the value inside self modified.
The direct fix is to take a reference:
match &mut self.my_id {
Some(id) => read(id),
_ => (),
}
This is more idiomatically written with an if let:
if let Some(id) = &mut self.my_id {
read(id);
}

Related

Is there a way of extracting a value from a &mut enum when the old one is discarded? [duplicate]

This question already has answers here:
How can I change enum variant while moving the field to the new variant?
(4 answers)
Closed 4 years ago.
I would like to extract a value from a pattern matched mutable reference and discard the old one.
This is a minimal example I've come up with:
fn main() {
#[derive(Debug)]
enum D<A> {
E1(A),
E2(A, A),
};
trait Zero<A> {
fn zero() -> A;
}
impl<A> D<A> {
pub fn push2(&mut self, e: A) {
match self {
D::E1(e1) => {
*self = D::E2(*e1, e);
}
_ => unimplemented!(),
}
}
pub fn push(&mut self, e: A)
where
A: Zero<A>,
{
match self {
D::E1(e1) => {
let mut r = A::zero();
std::mem::swap(&mut r, e1);
*self = D::E2(e, r);
}
_ => unimplemented!(),
};
}
}
impl Zero<i32> for i32 {
fn zero() -> i32 {
0
}
}
let mut d = D::E1(10);
d.push(11);
println!("{:?}", d);
}
playground
push2 fails with:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:17:39
|
17 | *self = D::E2(*e1, e);
| ^^^ cannot move out of borrowed content
I would like to achieve this without requiring the Copy trait as I have some boxed types inside and ideally would like to remove the need for the dummy variable (A::zero()).
If I understand your code, A will be some number because it implements Zero. The numeric values implement Copy in Rust, so you can use this to your advantage:
pub fn push(&mut self, e: A)
where
A: Zero<A> + Copy,
{
match self {
D::E1(e1) => *self = D::E2(e, *e1),
_ => unimplemented!(),
};
}
If you do not want to bound against Copy, you can use std::mem::replace as suggested:
pub fn push(&mut self, e: A)
where
A: Zero<A>,
{
use std::mem::replace;
match self {
D::E1(e1) => *self = D::E2(e, replace(e1, A::zero())),
_ => unimplemented!(),
};
}
That is the idiomatic way to do so.
You need the dummy element because you cannot do this:
D::E1(e1) => *self = D::E2(e, *e1),
The reason is that the compiler evaluates the parameters first, and *e1 tries to take the ownership of borrowed data, but that is forbidden.

Elegant way to borrow and return a mutable reference in Rust

I'm trying to return a mutable reference after doing some operation on it. This is best explained by a piece of code:
#[derive(PartialEq)]
pub enum Value {
Null,
Array(Vec<Value>),
}
impl Value {
pub fn new() -> Value {
Value::Array(Vec::new())
}
pub fn push<'a, T> (&'a mut self, value: T) -> Option<&'a mut Value>
where T:Into<Value> {
let temp = match *self {
Value::Array(ref mut vec) => {
vec.push(value.into());
true
},
_ => false,
};
if temp {
Some(self)
} else {
None
}
}
}
#[test]
fn push_test() {
let mut val = Value::new();
val.push(Value::Null);
assert!(val == Value::Array(vec![Value::Null]));
}
The play version is here. The workaround with boolean values is because I would be borrowing multiple times if I return Some(self) from within the match block. Is there an elegant way to implement the push function without using boolean values? If its possible to retain the function signature then its a bonus. Thank you!
The workaround with boolean values is because I would be borrowing multiple times if I return Some(self) from within the match block
Another option is to replace self temporally, so v can take the ownership of the vector (avoiding the borrow). After adding the new item to v, we reconstruct the self value:
// the lifetime 'a can be omitted
pub fn push<T>(&mut self, value: T) -> Option<&mut Value>
where T: Into<Value>
{
// replace put Value::Null on self and return the old value
match ::std::mem::replace(self, Value::Null) {
Value::Array(mut v) => {
v.push(value.into());
*self = Value::Array(v);
Some(self)
},
_ => None,
}
}

Cannot move out of borrowed content [E0507]

I'm writing a lexer in Rust to learn, but I'm stuck with two "cannot move out of borrowed content [E0507]" errors.
I tried all the solutions out there, but nothing seems to work: RefCell, clone(), by_ref(), changing the &mut self to self or &self or mut self, or dereferencing.
Here is my code:
struct Snapshot {
Index: u32,
}
struct Tokenizable<'a, T: 'a>
where T: Iterator
{
Index: u32,
Items: &'a T,
Snapshots: Vec<Snapshot>,
}
impl<'a, T> Tokenizable<'a, T>
where T: Iterator
{
fn new(items: &'a T) -> Tokenizable<'a, T> {
Tokenizable {
Index: 0,
Items: items,
Snapshots: Vec::new(),
}
}
fn end(&mut self) -> bool {
match self.Items.peekable().peek() {
Some(c) => false,
None => true,
}
}
fn peek(&mut self) -> Option<&T::Item> {
match self.Items.peekable().peek() {
Some(c) => Some(c),
None => None,
}
}
}
fn main() {}
error: cannot move out of borrowed content [E0507]
match self.Items.peekable().peek() {
^~~~~~~~~~
help: see the detailed explanation for E0507
error: borrowed value does not live long enough
match self.Items.peekable().peek() {
^~~~~~~~~~~~~~~~~~~~~
note: reference must be valid for the anonymous lifetime #1 defined on the block at 32:43...
fn peek(&mut self) -> Option<&T::Item> {
match self.Items.peekable().peek() {
Some(c) => Some(c),
None => None,
}
}
note: ...but borrowed value is only valid for the block at 32:43
fn peek(&mut self) -> Option<&T::Item> {
match self.Items.peekable().peek() {
Some(c) => Some(c),
None => None,
}
}
error: cannot move out of borrowed content [E0507]
match self.Items.peekable().peek() {
^~~~~~~~~~
help: see the detailed explanation for E0507
As you can see in the docs, the peekable function takes the iterator by value. Therefore it will only work if you own the iterator. However, in your code, Items is a shared reference to the iterator.
Solving this problem requires approaching it from a different angle. For instance, you could take the iterator by value in the constructor and adapt the struct to store the peekable iterator in the Items field.
Basically, what is to be learned from here is the fact that over complicating things and over engineering things almost always does more harm than good.
Final fixed code:
use std::iter::Peekable;
struct Snapshot {
index: u32
}
struct Tokenizable<T> where T: Iterator {
index : u32,
items : Peekable<T>,
snapshots : Vec<Snapshot>,
}
impl<T> Tokenizable<T> where T: Iterator {
fn new (items: T) -> Tokenizable<T> {
Tokenizable {
index : 0,
items : items.peekable (),
snapshots : Vec::new (),
}
}
fn end (&mut self) -> bool {
match self.items.peek () {
Some (c) => false,
None => true
}
}
fn peek (&mut self) -> Option<&<T as Iterator>::Item> {
match self.items.peek () {
Some (c) => Some (c),
None => None
}
}
}
fn main () {
let mut data = "Hello".chars ();
let tokenizable = Tokenizable::new (data);
}

How to do polymorphic IO from either a File or stdin in Rust?

I'm trying to implement a "polymorphic" Input enum which hides whether we're reading from a file or from a stdin. More concretely, I'm trying build an enum that will have a lines method that will in turn "delegate" that call to either a File wrapped into a BufReader or to a StdInLock (both of which have the lines() method).
Here's the enum:
enum Input<'a> {
Console(std::io::StdinLock<'a>),
File(std::io::BufReader<std::fs::File>)
}
I have three methods:
from_arg for deciding whether we're reading from a file or from a stdin by checking whether an argument (filename) was provided,
file for wrapping a file with a BufReader,
console for locking the stdin.
The implementation:
impl<'a> Input<'a> {
fn console() -> Input<'a> {
Input::Console(io::stdin().lock())
}
fn file(path: String) -> io::Result<Input<'a>> {
match File::open(path) {
Ok(file) => Ok(Input::File(std::io::BufReader::new(file))),
Err(_) => panic!("kita"),
}
}
fn from_arg(arg: Option<String>) -> io::Result<Input<'a>> {
Ok(match arg {
None => Input::console(),
Some(path) => try!(Input::file(path)),
})
}
}
As far as I understand, I have to implement both BufRead and Read traits for this to work. This is my attempt:
impl<'a> io::Read for Input<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
Input::Console(ref mut c) => c.read(buf),
Input::File(ref mut f) => f.read(buf),
}
}
}
impl<'a> io::BufRead for Input<'a> {
fn lines(self) -> Lines<Self> {
match self {
Input::Console(ref c) => c.lines(),
Input::File(ref f) => f.lines(),
}
}
fn consume(&mut self, amt: usize) {
match *self {
Input::Console(ref mut c) => c.consume(amt),
Input::File(ref mut f) => f.consume(amt),
}
}
fn fill_buf(&mut self) -> io::Result<&[u8]> {
match *self {
Input::Console(ref mut c) => c.fill_buf(),
Input::File(ref mut f) => f.fill_buf(),
}
}
}
Finally, the invocation:
fn load_input<'a>() -> io::Result<Input<'a>> {
Ok(try!(Input::from_arg(env::args().skip(1).next())))
}
fn main() {
let mut input = match load_input() {
Ok(input) => input,
Err(error) => panic!("Failed: {}", error),
};
for line in input.lines() { /* do stuff */ }
}
Complete example in the playground
The compiler tells me that I'm pattern matching wrongly and that I have mismatched types:
error[E0308]: match arms have incompatible types
--> src/main.rs:41:9
|
41 | / match self {
42 | | Input::Console(ref c) => c.lines(),
| | --------- match arm with an incompatible type
43 | | Input::File(ref f) => f.lines(),
44 | | }
| |_________^ expected enum `Input`, found struct `std::io::StdinLock`
|
= note: expected type `std::io::Lines<Input<'a>>`
found type `std::io::Lines<std::io::StdinLock<'_>>`
I tried to satisfy it with:
match self {
Input::Console(std::io::StdinLock(ref c)) => c.lines(),
Input::File(std::io::BufReader(ref f)) => f.lines(),
}
... but that doesn't work either.
I'm really out of my depth here, it seems.
The answer by #A.B. is correct, but it tries to conform to OP's original program structure. I want to have a more readable alternative for newcomers who stumble upon this question (just like I did).
use std::env;
use std::fs;
use std::io::{self, BufReader, BufRead};
fn main() {
let input = env::args().nth(1);
let reader: Box<dyn BufRead> = match input {
None => Box::new(BufReader::new(io::stdin())),
Some(filename) => Box::new(BufReader::new(fs::File::open(filename).unwrap()))
};
for line in reader.lines() {
println!("{:?}", line);
}
}
See the discussion in reddit from which I borrowed the code.
Note the dyn keyword before boxed BufRead. This pattern is called a trait object.
This is the simplest solution but will borrow and lock Stdin.
use std::fs::File;
use std::io::{self, BufRead, Read};
struct Input<'a> {
source: Box<BufRead + 'a>,
}
impl<'a> Input<'a> {
fn console(stdin: &'a io::Stdin) -> Input<'a> {
Input {
source: Box::new(stdin.lock()),
}
}
fn file(path: &str) -> io::Result<Input<'a>> {
File::open(path).map(|file| Input {
source: Box::new(io::BufReader::new(file)),
})
}
}
impl<'a> Read for Input<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.source.read(buf)
}
}
impl<'a> BufRead for Input<'a> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.source.fill_buf()
}
fn consume(&mut self, amt: usize) {
self.source.consume(amt);
}
}
Due to default trait methods, Read and BufRead are fully implemented for Input. So you can call lines on Input.
let input = Input::file("foo.txt").unwrap();
for line in input.lines() {
println!("input line: {:?}", line);
}
If you're willing to restructure you're code a bit, you can actually get away without doing dynamic dispatch. You just need to make sure whatever code is using the reader is wrapped in it's own function and the concrete types of the arguments for that function are known at compile time.
So if we eschew the enum Input idea for a moment, and building on #Yerke's answer, we can do:
use std::env;
use std::fs;
use std::io::{BufRead, BufReader, Read};
fn main() {
let input = env::args().nth(1);
match input {
Some(filename) => output_lines(fs::File::open(filename).unwrap()),
None => output_lines(std::io::stdin()),
};
}
fn output_lines<R: Read>(reader: R) {
let buffer = BufReader::new(reader);
for line in buffer.lines() {
println!("{:?}", line);
}
}
Because we have a concrete type for R each time we call output_lines, the compiler can monomorphize the output_lines function and do static dispatch. In addition to being less complicated code in my opinion (no need for Box wrapping), it's also slightly faster and the compiler can do more optimizations.

Mutating one field while iterating over another immutable field

Given the following program:
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&mut self, s: &str) {
self.output().push_str(s);
}
fn data(&self) -> &Data;
fn generate_items(&mut self) {
for item in self.data().items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
}
fn output(&mut self) -> &mut String;
}
struct MyGenerator<'a> {
data: &'a Data,
output: String,
}
impl<'a> MyGenerator<'a> {
fn generate(mut self) -> String {
self.generate_items();
self.output
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&self) -> &Data {
self.data
}
fn output(&mut self) -> &mut String {
&mut self.output
}
}
fn main() {
let data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &data,
output: String::new(),
};
let output = generator.generate();
println!("{}", output);
}
The following errors are produced trying to compile it:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:26
|
13 | for item in self.data().items.iter() {
| ---- - immutable borrow ends here
| |
| immutable borrow occurs here
14 | match *item {
15 | "foo" => self.append("it was foo\n"),
| ^^^^ mutable borrow occurs here
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:16:22
|
13 | for item in self.data().items.iter() {
| ---- - immutable borrow ends here
| |
| immutable borrow occurs here
...
16 | _ => self.append("it was something else\n"),
| ^^^^ mutable borrow occurs here
What is the proper way to structure the code so that the mutable field output can be written to while iterating over the immutable field data? Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.
This is a common issue in Rust; the typical way of solving it is the replace dance. This involves making more of the data and methods use mutable references:
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&mut self, s: &str) {
self.output().push_str(s);
}
fn data(&mut self) -> &mut Data;
fn generate_items(&mut self) {
// Take the data. The borrow on self ends after this statement.
let data = std::mem::replace(self.data(), Data { items: vec![] });
// Iterate over the local version. Now append can borrow all it wants.
for item in data.items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
// Put the data back where it belongs.
std::mem::replace(self.data(), data);
}
fn output(&mut self) -> &mut String;
}
struct MyGenerator<'a> {
data: &'a mut Data,
output: String,
}
impl<'a> MyGenerator<'a> {
fn generate(mut self) -> String {
self.generate_items();
self.output
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&mut self) -> &mut Data {
self.data
}
fn output(&mut self) -> &mut String {
&mut self.output
}
}
fn main() {
let mut data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &mut data,
output: String::new(),
};
let output = generator.generate();
println!("{}", output);
}
The thing to realize is that the compiler is right to complain. Imagine if calling output() had the side effect of mutating the thing that is referenced by the return value of data() Then the iterator you're using in the loop could get invalidated. Your trait functions have the implicit contract that they don't do anything like that, but there is no way of checking this. So the only thing you can do is temporarily assume full control over the data, by taking it out.
Of course, this pattern breaks unwind safety; a panic in the loop will leave the data moved out.
Assume the indirection through the Generator trait is being used to share similar logic with other structs, so accessing MyStruct's fields from the trait's default method implementations need to be done through accessor methods like this.
Then it's impossible.
The compiler recognizes access to different fields when it sees such fields directly; it does not break abstraction boundaries to peek inside the functions called.
There have been discussions about adding attributes on the methods to specifically mention which field is accessed by which method:
the compiler would enforce that a method does not touch any field NOT mentioned in the attribute
the compiler could then use the knowledge that said method only operates on a subset of the fields
however... this is for non-virtual methods.
For a trait this gets significantly more complicated because a trait does not have fields, and each implementer may have a different set of fields!
So now what?
You will need to change your code:
you can split the trait in two, and require two objects (one to iterate, one to mutate)
you can "hide" the mutability of the append method, forcing users to use interior mutability
...
You can use RefCell:
RefCell uses Rust's lifetimes to implement 'dynamic borrowing', a
process whereby one can claim temporary, exclusive, mutable access to
the inner value. Borrows for RefCells are tracked 'at runtime',
unlike Rust's native reference types which are entirely tracked
statically, at compile time. Because RefCell borrows are dynamic it
is possible to attempt to borrow a value that is already mutably
borrowed; when this happens it results in thread panic.
use std::cell::{RefCell, RefMut};
struct Data {
pub items: Vec<&'static str>,
}
trait Generator {
fn append(&self, s: &str) {
self.output().push_str(s);
}
fn data(&self) -> &Data;
fn generate_items(&self) {
for item in self.data().items.iter() {
match *item {
"foo" => self.append("it was foo\n"),
_ => self.append("it was something else\n"),
}
}
}
fn output(&self) -> RefMut<String>;
}
struct MyGenerator<'a> {
data: &'a Data,
output: RefCell<String>,
}
impl<'a> MyGenerator<'a> {
fn generate(self) -> String {
self.generate_items();
self.output.into_inner()
}
}
impl<'a> Generator for MyGenerator<'a> {
fn data(&self) -> &Data {
self.data
}
fn output(&self) -> RefMut<String> {
self.output.borrow_mut()
}
}
fn main() {
let data = Data {
items: vec!["foo", "bar", "baz"],
};
let generator = MyGenerator {
data: &data,
output: RefCell::new(String::new()),
};
let output = generator.generate();
println!("{}", output);
}
Rust playground

Resources