Cannot move out of borrowed content [E0507] - rust

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);
}

Related

Immutable Borrow in None Option

Example Code:
struct Foo;
impl Foo {
fn foo(&mut self) -> Result<&i32, String> {
match self.bar() {
Some(d) => Ok(d),
None => {
if self.check() {
Err(String::from("Error type 1"))
} else {
Err(String::from("Error type 2"))
}
}
}
}
fn bar(&mut self) -> Option<&i32> {
todo!()
}
fn check(&self) -> bool {
todo!()
}
}
Rust playground Code
Problem
In the Foo::foo function:
self.bar() requires mutable borrow.
self.check() requires immutable borrow.
The above code fails to compile. The lifetime checker complains about the two borrow (mutable and immutable).
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src/lib.rs:8:20
|
4 | fn foo(&mut self) -> Result<&i32, String> {
| - let's call the lifetime of this reference `'1`
5 | match self.bar() {
| ---------- mutable borrow occurs here
6 | Some(d) => Ok(d),
| ----- returning this value requires that `*self` is borrowed for `'1`
7 | None => {
8 | if self.check() {
| ^^^^^^^^^^^^ immutable borrow occurs here
Questions
Question 1
Why the compiler prevent me to compile this code?
Clearly I am missing something here, but...
The immutable borrow (i.e. self.check()) only happens in the None branch. The previous mutable borrow (i.e. self.bar()) should not bring any impact there, should it?
The same code might be written:
if let Some(d) = self.bar() {
return Ok(d);
}
// What lifetime of `self.bar` is needed at this point?
if self.check() {
// ...
} else {
// ...
}
Question 2
How can I solve this problem?
Please note:
I do not want to move the check (i.e. self.check()) before the match. Merely because of performances: self.check might be expensive and in the "cold" path. If self.bar() returns Some I want to return as soon as possible from the function.
I do not want to to introduce runtime overhead. (E.g., dynamic check for borrow -> RefCell).
Of course, this is a dummy example. Just for the sake of demonstration. So be aware about it. For example:
&'a i32 represent an example returned "data" that requires lifetime. In my real code you can imagine I have a complex object which holds some references (and thus require lifetime). E.g., struct ComplexObject<'a>.
Answer 1
The problem is that in Some(d) => Ok(d) you're still holding a reference &i32 with the same lifetime as &mut self of the self.bar() call. Lifetime elisions hide this, but the code would desugar into something like this:
fn bar<'a>(&'a mut self) -> Option<&'a i32> {
todo!()
}
The self.bar() result has lifetime 'a, so does d in Some(d). Since you're returning d from the function, self.bar() needs to stay mutably borrowed until the end of the function. This makes self.check() impossible to be borrowed.
To better visualize the issue:
use std::rc::Rc;
struct Foo;
impl Foo {
fn foo<'b>(&'b mut self) -> Result<&'b i32, String> {
match self.bar() { // --+- "&'a mut self" borrowed
Some(d) => Ok(d), // --+- "'a" becomes "'b"
None => { // |
if self.check() { // --+- "&'c self" borrow failed attempt
Err(String::from("Error type 1"))
} else { // |
Err(String::from("Error type 2"))
} // |
} // |
} // |
} // --+- "&'a mut self" valid until here
fn bar<'a>(&'a mut self) -> Option<&'a i32> {
todo!()
}
fn check<'c>(&'c self) -> bool {
todo!()
}
}
The return value of self.foo is &'b i32, which needs the same lifetime as the return value of bar, so 'a needs to live at least as long as 'b, thus &'a mut self borrowed in self.bar stays borrowed until the end of self.foo.
Answer 2
There's three options I'd consider:
Change the return value of bar to be Option<i32> if moving is an option:
struct Foo;
impl Foo {
fn foo(&mut self) -> Result<i32, String> {
match self.bar() {
Some(d) => Ok(d),
None => {
if self.check() {
Err(String::from("Error type 1"))
} else {
Err(String::from("Error type 2"))
}
}
}
}
fn bar(&mut self) -> Option<i32> {
todo!()
}
fn check(&self) -> bool {
todo!()
}
}
Split self.bar() into two separate functions, one that does the mutable operation and moves the ownership from the function to the callee, and one that returns Option<&i32> but borrows immutably:
struct Foo;
impl Foo {
fn foo(&mut self) -> Result<&i32, String> {
let bar = self.bar_mut();
match self.bar(bar) {
Some(d) => Ok(d),
None => {
if self.check() {
Err(String::from("Error type 1"))
} else {
Err(String::from("Error type 2"))
}
}
}
}
fn bar_mut(&mut self) -> Option<i32> {
todo!()
}
fn bar(&self, bar: Option<i32>) -> Option<&i32> {
todo!()
}
fn check(&self) -> bool {
todo!()
}
}
Use Rc for multiple ownership if you cannot move the object at all:
use std::rc::Rc;
struct Foo;
impl Foo {
fn foo(&mut self) -> Result<Rc<i32>, String> {
match self.bar() {
Some(d) => Ok(d),
None => {
if self.check() {
Err(String::from("Error type 1"))
} else {
Err(String::from("Error type 2"))
}
}
}
}
fn bar(&mut self) -> Option<Rc<i32>> {
// Rc::clone the value here
todo!()
}
fn check(&self) -> bool {
todo!()
}
}

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

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);
}

How do I mutate in a match which borrows an immutable value?

I can understand borrowing/ownership concepts in Rust, but I have no idea how to work around this case:
use std::collections::{HashMap, HashSet};
struct Val {
t: HashMap<u16, u16>,
l: HashSet<u16>,
}
impl Val {
fn new() -> Val {
Val {
t: HashMap::new(),
l: HashSet::new(),
}
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
self.l.insert(v);
}
fn remove(&mut self, v: &u16) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(r) => self.remove(r),
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.l.len());
}
playground
The compiler has the error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:28:24
|
26 | match self.t.get(&v) {
| ------ immutable borrow occurs here
27 | None => false,
28 | Some(r) => self.remove(r),
| ^^^^^------^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
I don't understand why I can't mutate in the match arm when I did a get (read value) before; the self.t.get is finished when the mutation via remove begins.
Is this due to scope of the result (Option<&u16>) returned by the get? It's true that the lifetime of the result has a scope inside the match expression, but this design-pattern is used very often (mutate in a match expression).
How do I work around the error?
The declaration of function HashMap::<K,V>::get() is, a bit simplified:
pub fn get<'s>(&'s self, k: &K) -> Option<&'s V>
This means that it returns an optional reference to the contained value, not the value itself. Since the returned reference points to a value inside the map, it actually borrows the map, that is, you cannot mutate the map while this reference exists. This restriction is there to protect you, what would happen if you remove this value while the reference is still alive?
So when you write:
match self.t.get(&v) {
None => false,
//r: &u16
Some(r) => self.remove(r)
}
the captured r is of type &u16 and its lifetime is that of self.t, that is, it is borrowing it. Thus you cannot get a mutable reference to self, that is needed to call remove.
The simplest solution for your problem is the clone() solves every lifetime issue pattern. Since your values are of type u16, that is Copy, it is actually trivial:
match self.t.get(&v) {
None => false,
//r: u16
Some(&r) => self.remove(&r)
}
Now r is actually of type u16 so it borrows nothing and you can mutate self at will.
If your key/value types weren't Copy you could try and clone them, if you are willing to pay for that. If not, there is still another option as your remove() function does not modify the HashMap but an unrelated HashSet. You can still mutate that set if you take care not to reborrow self:
fn remove2(v: &u16, l: &mut HashSet<u16>) -> bool {
l.remove(v)
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
//selt.t is borrowed, now we mut-borrow self.l, no problem
Some(r) => Self::remove2(r, &mut self.l)
}
}
You are trying to remove value from HashMap by using value you get, not key.
Only line 26 is changed Some(_) => self.remove(&v)
This will work:
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(_) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(1100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
play.rust
It seems that the following solution is good for primitive types like here u16. For other types, the ownership is moved.
use std::collections::HashMap;
struct Val {
t: HashMap<u16, u16>,
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new() }
}
fn set(&mut self, k: u16, v: u16) {
self.t.insert(k, v);
}
fn remove(&mut self, v: &u16) -> bool {
match self.t.remove(v) {
None => false,
_ => true,
}
}
fn do_work(&mut self, v: u16) -> bool {
match self.t.get(&v) {
None => false,
Some(&v) => self.remove(&v)
}
}
}
fn main() {
let mut v = Val::new();
v.set(123, 100);
v.set(100, 1234);
println!("Size before: {}", v.t.len());
println!("Work: {}", v.do_work(123));
println!("Size after: {}", v.t.len());
}
For other types, we must clone the value:
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
struct Val {
t: HashMap<String, String>,
l: HashSet<String>
}
impl Val {
fn new() -> Val {
Val { t: HashMap::new(), l: HashSet::new() }
}
fn set(&mut self, k: String, v: String) {
self.l.insert(v.clone());
self.t.insert(k, v);
}
fn remove(&mut self, v: &String) -> bool {
self.l.remove(v)
}
fn do_work(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => {
let x = v.clone();
self.remove(&x)
}
}
}
fn do_task(&mut self, i: &String) -> bool {
match self.t.get(i) {
None => false,
Some(v) => self.l.insert(v.clone())
}
}
}
fn main() {
let mut v = Val::new();
v.set("AA".to_string(), "BB".to_string());
v.set("BB".to_string(), "CC".to_string());
println!("Start: {:#?}", v);
println!("Size before: {}", v.l.len());
println!("Work: {}", v.do_work(&"AA".to_string()));
println!("Size after: {}", v.l.len());
println!("After: {:#?}", v);
println!("Task [Exist]: {}", v.do_task(&"BB".to_string()));
println!("Task [New]: {}", v.do_task(&"AA".to_string()));
println!("End: {:#?}", v);
}
But i'd like a solution that has no allocation

How to define an iterator in Rust over a struct that contains items that are iterable?

How does one define an iterator in Rust over a struct that contains items that are already iterable? Here's one attempt at the iterator
use rand;
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter {
foo: Iterator,
bar: Iterator,
}
// Method that provides the iterator for use
impl Foo {
fn iter(&self) -> FooIter {
FooIter {
foo: self.foo.iter().peek(),
bar: self.bar.iter().peek(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl Iterator for FooIter {
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next()
} else {
self.bar.next()
}
}
(Some(_), None) => self.foo.next(),
(None, Some(_)) => self.bar.next(),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
In short, the struct Foo contains two vectors and I'd like an iterator that jumps back and forth between the two elements randomly. Certainly, there are many mistakes here, but at the core, I don't understand how to create a struct that carries the iterators for the items foo and far because Rust defines iterators as a trait and not a type.
You must at some point define what Item the Iterator will produce, for example Iterator<Item = &'a f64>. Let simplify and transform to Iterator<Item = f64>, because f64 is Copy so it's often better to avoid the reference if you don't need it.
So, then we will have compile error:
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = f64> + 'static)` cannot be known at compilation time
--> src/main.rs:11:5
|
11 | foo: std::iter::Iterator<Item = f64>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = f64> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: only the last field of a struct may have a dynamically sized type
To avoid dynamic type and fix the error at the same time, let's define some generic type:
// Iterator for the structure
struct FooIter<F, I> {
foo: F,
bar: I,
}
We add the necessary on our implementation of Iterator:
impl<F, I> Iterator for FooIter<F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
And we must change how we generate FooIter, this time we will use a magic keyword impl, this avoid to write the real type of the Iterator that can be very long and unclear, the compiler will infer the type for us. Also, we must bound the type to the lifetime of &self because it must be borrow as long as the iterator live, simply declare 'a lifetime and add + 'a will do the job:
fn iter<'a>(
&'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(),
bar: self.bar.iter().copied(),
}
}
Here we finish the basic, the next problem is that your code doesn't produce Bar type in next(), so we must correct your code, also it's would be nice to create a propre random generator. So here the final snippet:
use rand::{rngs::ThreadRng, thread_rng, Rng};
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter<'r, F, I> {
foo: F,
bar: I,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(), // nigthly feature, use cloned() for stable
bar: self.bar.iter().copied(),
rng,
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<'r, F, I> Iterator for FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
if self.rng.gen() {
self.foo
.next()
.map(|x| Bar::MyFloat(x))
.or_else(|| self.bar.next().map(|x| Bar::MyInt(x)))
} else {
self.bar
.next()
.map(|x| Bar::MyInt(x))
.or_else(|| self.foo.next().map(|x| Bar::MyFloat(x)))
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter(&mut thread_rng()) {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
Note, if you still want a Peekable<Iterator> then just do:
struct FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
foo: Peekable<F>,
bar: Peekable<I>,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied().peekable(),
bar: self.bar.iter().copied().peekable(),
rng,
}
}
}
#Stargateur largely has me sorted, but I wanted to include two separate codes to complete things. The following is the fixed code that's slightly closer to my original attempt, which works on Rust 1.34.1:
// Structure of items
struct Foo {
foo: Vec<f64>,
far: Vec<i64>,
}
// Iterator for the structure
struct FooIter<FloatIter, IntIter>
where
FloatIter: Iterator<Item = f64>,
IntIter: Iterator<Item = i64>,
{
foo: std::iter::Peekable<FloatIter>,
far: std::iter::Peekable<IntIter>,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a>(
&'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().cloned().peekable(),
far: self.far.iter().cloned().peekable(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<FloatIter, IntIter> Iterator for FooIter<FloatIter, IntIter>
where
FloatIter: Iterator<Item = f64>,
IntIter: Iterator<Item = i64>,
{
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next().map(|x| Bar::MyFloat(x))
} else {
self.far.next().map(|x| Bar::MyInt(x))
}
}
(Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x)),
(None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x)),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
far: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
What helped me understand what was going on is that FooIter parametrizes its arguments on generic types. These types are inferred by using impl Trait in the return position within the iter method for Foo. That said, I was able to write a similar code without using this inference:
extern crate rand;
// Structure of items
struct Foo {
foo: Vec<f64>,
far: Vec<i64>,
}
// Iterator for the structure
struct FooIter<'a> {
foo: std::iter::Peekable<std::slice::Iter<'a, f64>>,
far: std::iter::Peekable<std::slice::Iter<'a, i64>>,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a>(&'a self) -> FooIter<'a> {
FooIter {
foo: self.foo.iter().peekable(),
far: self.far.iter().peekable(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<'a> Iterator for FooIter<'a> {
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next().map(|x| Bar::MyFloat(x.clone()))
} else {
self.far.next().map(|x| Bar::MyInt(x.clone()))
}
}
(Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x.clone())),
(None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x.clone())),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
far: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
This is almost certainly the wrong way to do things, but I wanted to see if it was possible. I determined the iterator type by compiling the code:
fn main() {
let x = vec![1.2, 2.3, 3.4];
let y: i32 = x.iter().peekable();
}
which gave the compiler error:
error[E0308]: mismatched types
--> junk.rs:4:19
|
4 | let y: i32 = x.iter().peekable();
| ^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::iter::Peekable`
|
= note: expected type `i32`
found type `std::iter::Peekable<std::slice::Iter<'_, {float}>>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
This contains the type of what I was looking for. Again, this is almost certainly the wrong thing to do, but it helped me understand the provided answer.

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,
}
}

Resources