How do I convert a mutable reference to self into an immutable reference to be used as an argument for a method? - methods

I have following code that can't be compiled:
struct A {
x: i32,
}
impl A {
fn add_assign(&mut self, other: &Self) {
self.x += other.x;
}
fn double(&mut self) {
self.add_assign(self);
}
}
The error is:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/lib.rs:11:9
|
11 | self.add_assign(self);
| ^^^^^----------^----^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
How to pass self as the argument of add_assign? I have tried &self, *self, &*self without success.

For the current version of the question
fn add_assign(&mut self, other: &Self)
Your request is impossible.
You cannot have a mutable reference and an immutable reference to the same value at the same time. This is a fundamental aspect of Rust.
Please re-read the rules of references.
See also:
Cannot borrow as mutable because it is also borrowed as immutable
For the first version of the question
fn add_assign(&mut self, other: Self)
Your request is impossible.
You need one instance of struct A to call the method on and another instance of A to pass as the argument. Your type does not implement Copy or Clone or provide any equivalent methods so there is no way to get a second instance.
Beyond that, there's no universal way to take a mutable reference to a value and get an owned value out of it.
See also:
Cannot move out of borrowed content / cannot move out of behind a shared reference
Workarounds
If you implement Copy or Clone, then you can get a second value from the original and then call either of your versions.
If you implemented Copy:
(other: Self)
self.add_assign(*self);
(other: &Self)
let other = *self;
self.add_assign(&other);
If only Clone:
(other: Self)
self.add_assign(self.clone());
(other: &Self)
self.add_assign(&self.clone());
You probably want to implement the AddAssign trait to provide syntax sugar. Assuming you've implemented Copy:
impl A {
fn double(&mut self) {
*self += *self;
}
}
impl std::ops::AddAssign<Self> for A {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
}
}
Stargateur's comment may also be applicable, as i32 implements Copy:
impl A {
fn double(&mut self) {
*self += self.x;
}
}
impl std::ops::AddAssign<i32> for A {
fn add_assign(&mut self, other: i32) {
self.x += other;
}
}

Related

Access iterator inside its for loop

I am testing a custom bi-directional iterator in rust but i ran into error
error[E0382]: borrow of moved value: `iter`
--> src/main.rs:40:13
|
37 | let mut iter = BiIterator::from(vec![1, 2, 3]);
| -------- move occurs because `iter` has type `BiIterator<i32>`, which does not implement the `Copy` trait
38 | for i in iter {
| ----
| |
| `iter` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&iter`
39 | if i == 3 {
40 | iter.position(0);
| ^^^^^^^^^^^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `iter`
reproducable code
The for loop is taking ownership of the iterator. To use the iterator inside the loop body, you need to desugar the for loop into while let:
while let Some(i) = iter.next() {
if i == 3 {
iter.position(0);
}
println!("{}", i);
}
If you want to make your iterator usable from a for loop, you'll need to invest a bit of extra effort. You can implement Iterator for &BiIterator, and use interior mutability for pos, so position() can take &self:
// don't need RefCell because we're just mutating a number
use std::cell::Cell;
struct BiIterator<T> {
values: Vec<T>,
pos: Cell<usize>,
}
impl<T: Clone> Iterator for &BiIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.pos.set(self.pos.get() + 1);
self.values.get(self.pos.get() - 1).cloned()
}
}
impl<T> BiIterator<T> {
pub fn position(&self, new_pos: usize) {
self.pos.set(new_pos);
}
pub fn prev(&mut self) {
self.pos.set(self.pos.get() - 1);
}
}
impl<T> std::convert::From<Vec<T>> for BiIterator<T> {
fn from(input: Vec<T>) -> Self {
Self {
values: input,
pos: Cell::new(0),
}
}
}
With these changes you can finally use for i in &iter as per the compiler's original suggestion:
fn main() {
let iter = BiIterator::from(vec![1, 2, 3]);
for i in &iter {
if i == 3 {
iter.position(0);
}
println!("{}", i);
}
}
The above implements some additional changes:
no need for the Copy bound on T, since you're only cloning it. Any T that is Copy is automatically Clone, and cloning it can be expected to just perform the cheap copy.
bounds are almost never needed on the struct; put them just on the impl instead.
replace the if/else if let/else chain with a match or, better yet, with Option::cloned().

Is it possible to unpack a tuple into method arguments?

Unpacking a tuple as arguments and calling a function with those values is covered by Is it possible to unpack a tuple into function arguments?, but is it possible to do the same trick on methods?
#![feature(fn_traits)]
struct Foo;
impl Foo {
fn method(&self, a: i32, b: i32) {
println!("{:?}, {:?}", a, b);
}
}
fn main() {
let foo = Foo;
let tuple = (10, 42);
// does not compile
//foo.method.call(tuple);
// nor this one
//std::ops::Fn::call(&foo.method, tuple);
}
For both I get the following error:
error[E0615]: attempted to take value of method `method` on type `Foo`
--> src/main.rs:20:9
|
20 | foo.method.call(tuple);
| ^^^^^^ help: use parentheses to call the method: `method(...)`
I do not control the method I call, so changing the signature to accept tuples is not an option.
Methods are functions that
Are associated with a type (called associated functions). Most people are familiar with "constructor" associated functions like new. These are referenced as Type::function_name.
Take some kind of Self as the first argument.
Thus you need to use Foo::method and provide a matching self:
#![feature(fn_traits)]
struct Foo;
impl Foo {
fn method(&self, a: i32, b: i32) {
println!("{:?}, {:?}", a, b);
}
}
fn main() {
let foo = Foo;
let tuple = (&foo, 10, 42);
std::ops::Fn::call(&Foo::method, tuple);
}
See also:
Fully-qualified syntax
What types are valid for the `self` parameter of a method?

How to store method pointers in a HashMap and call them

I am trying to write a chip8 emulator and the borrow checker is giving me a hard time.
The idea is to decode an opcode through looking up a method pointer inside a HashMap and then executing this method pointer but I cannot get the mutable method pointers to work correctly:
struct Chip8 {
opcode: u16,
//... other fields
jump_table: HashMap<u16, Box<fn(&mut Chip8)>>,
}
Function using the pointers:
fn execute_decoded(&mut self, key: u16) {
let func = self.jump_table.get(&key);
match func {
Some(func) => func(self),
None => {
println!("invalid op: {}", self.opcode);
sleep(Duration::from_millis(10000));
return;
}
}();
self.program_counter = self.program_counter + 2;
}
The checker complains:
cannot borrow `*self` as mutable because `self.jump_table` is also borrowed as immutable
--> main.rs:168:36
|
165 | let func = self.jump_table.get(&key);
| --------------- immutable borrow occurs here
...
168 | Some(func) => func(self),
| ^^^^ mutable borrow occurs here
...
178 | }
| - immutable borrow ends here
I do not understand why this error is happening.
Why is self.jump_table.get(&key) borrowing at all? Based on the signature of execute_decoded, I was assuming that it works on a mutable borrowed version of self and no additional borrowing is needed.
There's no reason to Box the function pointers in the HashMap, that only introduces unneeded indirection.
As has already been mentioned, you are borrowing the function pointer. The thing is, there's no reason to. You can just copy the function pointer to disassociate it from the HashMap:
use std::collections::HashMap;
struct Chip8 {
jump_table: HashMap<u16, fn(&mut Chip8)>,
}
impl Chip8 {
fn execute_decoded(&mut self, key: u16) {
let func = self.jump_table.get(&key).map(|x| *x);
match func {
Some(func) => func(self),
None => {
println!("invalid op");
}
};
}
}
fn main() {}
A HashMap in Rust owns everything inside of it. In order to get your function pointer you are borrowing it with let func = self.jump_table.get(&key);. So now, func is immutably borrowing self.jump_table (which is an element of self).
The issue is that you are then trying to pass all of self into func. This would be fine if you were passing in self immutably, as you can borrow self immutably as many times as you want. However, since you are trying to mutably borrow self the compiler will not allow you to do so since you have just immutably borrowed a portion of self (specifically self.jump_table).
One way to fix this is to split up your Chip8 struct into smaller structs, such that you can pass all of the necessary information into func without also passing in jump_table.

Borrow mutable and immutable reference in the same block [duplicate]

Why does the call self.f2() in the following code trip the borrow checker? Isn't the else block in a different scope? This is quite a conundrum!
use std::str::Chars;
struct A;
impl A {
fn f2(&mut self) {}
fn f1(&mut self) -> Option<Chars> {
None
}
fn f3(&mut self) {
if let Some(x) = self.f1() {
} else {
self.f2()
}
}
}
fn main() {
let mut a = A;
}
Playground
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:16:13
|
13 | if let Some(x) = self.f1() {
| ---- first mutable borrow occurs here
...
16 | self.f2()
| ^^^^ second mutable borrow occurs here
17 | }
| - first borrow ends here
Doesn't the scope of the borrow for self begin and end with the self.f1() call? Once the call from f1() has returned f1() is not using self anymore hence the borrow checker should not have any problem with the second borrow. Note the following code fails too...
// ...
if let Some(x) = self.f1() {
self.f2()
}
// ...
Playground
I think the second borrow should be fine here since f1 and f3 are not using self at the same time as f2.
I put together an example to show off the scoping rules here:
struct Foo {
a: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo: {}", self.a);
}
}
fn generate_temporary(a: i32) -> Option<Foo> {
if a != 0 { Some(Foo { a: a }) } else { None }
}
fn main() {
{
println!("-- 0");
if let Some(foo) = generate_temporary(0) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(foo) = generate_temporary(1) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 1 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 2 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
}
This prints:
-- 0
None
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
None
Foo: 1
-- 1
In short, it seems that the expression in the if clause lives through both the if block and the else block.
On the one hand it is not surprising since it is indeed required to live longer than the if block, but on the other hand it does indeed prevent useful patterns.
If you prefer a visual explanation:
if let pattern = foo() {
if-block
} else {
else-block
}
desugars into:
{
let x = foo();
match x {
pattern => { if-block }
_ => { else-block }
}
}
while you would prefer that it desugars into:
bool bypass = true;
{
let x = foo();
match x {
pattern => { if-block }
_ => { bypass = false; }
}
}
if not bypass {
else-block
}
You are not the first one being tripped by this, so this may be addressed at some point, despite changing the meaning of some code (guards, in particular).
It's annoying, but you can work around this by introducing an inner scope and changing the control flow a bit:
fn f3(&mut self) {
{
if let Some(x) = self.f1() {
// ...
return;
}
}
self.f2()
}
As pointed out in the comments, this works without the extra braces. This is because an if or if...let expression has an implicit scope, and the borrow lasts for this scope:
fn f3(&mut self) {
if let Some(x) = self.f1() {
// ...
return;
}
self.f2()
}
Here's a log of an IRC chat between Sandeep Datta and mbrubeck:
mbrubeck: std:tr::Chars contains a borrowed reference to the string that created it. The full type name is Chars<'a>. So f1(&mut self) -> Option<Chars> without elision is f1(&'a mut self) -> Option<Chars<'a>> which means that self remains borrowed as long as
the return value from f1 is in scope.
Sandeep Datta: Can I use 'b for self and 'a for Chars to avoid this problem?
mbrubeck: Not if you are actually returning an iterator over something from self. Though if you can make a function from &self -> Chars (instead of &mut self -> Chars) that would fix the issue.
As of Rust 2018, available in Rust 1.31, the original code will work as-is. This is because Rust 2018 enables non-lexical lifetimes.
A mutable reference is a very strong guarantee: that there's only one pointer to a particular memory location. Since you've already had one &mut borrow, you can't also have a second. That would introduce a data race in a multithreaded context, and iterator invalidation and other similar issues in a single-threaded context.
Right now, borrows are based on lexical scope, and so the first borrow lasts until the end of the function, period. Eventually, we hope to relax this restriction, but it will take some work.
Here is how you can get rid of the spurious errors. I am new to Rust so there may be serious errors in the following explanation.
use std::str::Chars;
struct A<'a> {
chars: Chars<'a>,
}
The 'a here is a lifetime parameter (just like template parameters in C++). Types can be parameterised by lifetimes in Rust.
The Chars type also takes a lifetime parameter. What this implies is that the Chars type probably has a member element which needs a lifetime parameter. Lifetime parameters only make sense on references (since lifetime here actually means "lifetime of a borrow").
We know that Chars needs to keep a reference to the string from which it was created, 'a will probably be used to denote the source string's lifetime.
Here we simply supply 'a as the lifetime parameter to Chars telling the Rust compiler that the lifetime of Chars is the same as the lifetime of the struct A. IMO "lifetime 'a of type A" should be read as "lifetime 'a of the references contained in the struct A".
I think the struct implementation can be parameterised independently from the struct itself hence we need to repeat the parameters with the impl keyword. Here we bind the name 'a to the lifetime of the struct A.
impl<'a> A<'a> {
The name 'b is introduced in the context of the function f2. Here it is used to bind with the lifetime of the reference &mut self.
fn f2<'b>(&'b mut self) {}
The name 'b is introduced in the context of the function f1.This 'b does not have a direct relationship with the 'b introduced by f2 above.
Here it is used to bind with the lifetime of the reference &mut self. Needless to say this reference also does not have any relationship with the &mut self in the previous function, this is a new independent borrow of self.
Had we not used explicit lifetime annotation here Rust would have used its lifetime elision rules to arrive at the following function signature...
//fn f1<'a>(&'a mut self) -> Option<Chars<'a>>
As you can see this binds the lifetime of the reference &mut self parameter to the lifetime of the Chars object being returned from this function (this Chars object need not be the same as self.chars) this is absurd since the returned Chars will outlive the &mut self reference. Hence we need to separate the two lifetimes as follows...
fn f1<'b>(&'b mut self) -> Option<Chars<'a>> {
self.chars.next();
Remember &mut self is a borrow of self and anything referred to by &mut self is also a borrow. Hence we cannot return Some(self.chars) here. self.chars is not ours to give (Error: cannot move out of borrowed content.).
We need to create a clone of self.chars so that it can be given out.
Some(self.chars.clone())
Note here the returned Chars has the same lifetime as the struct A.
And now here is f3 unchanged and without compilation errors!
fn f3<'b>(&'b mut self) {
if let Some(x) = self.f1() { //This is ok now
} else {
self.f2() //This is also ok now
}
}
The main function just for completeness...
fn main() {
let mut a = A { chars:"abc".chars() };
a.f3();
for c in a.chars {
print!("{}", c);
}
}
I have updated the code the make the lifetime relationships clearer.

What types are valid for the `self` parameter of a method?

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:
use std::rc::Rc;
use std::sync::Arc;
struct Bar;
impl Bar {
fn consuming(self) {}
fn reference(&self) {}
fn mutable_reference(&mut self) {}
fn boxed(self: Box<Bar>) {}
fn ref_count(self: Rc<Bar>) {}
fn atomic_ref_count(self: Arc<Bar>) {}
}
fn main() {}
Yields these errors:
error[E0308]: mismatched method receiver
--> a.rs:11:18
|
11 | fn ref_count(self: Rc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
|
= note: expected type `Bar`
= note: found type `std::rc::Rc<Bar>`
error[E0308]: mismatched method receiver
--> a.rs:12:25
|
12 | fn atomic_ref_count(self: Arc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
|
= note: expected type `Bar`
= note: found type `std::sync::Arc<Bar>`
This is with Rust 1.15.1.
Before Rust 1.33, there are only four valid method receivers:
struct Foo;
impl Foo {
fn by_val(self: Foo) {} // a.k.a. by_val(self)
fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
fn by_box(self: Box<Foo>) {} // no short form
}
fn main() {}
Originally, Rust didn't have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.
As of Rust 1.33, some additional selected types are available for use as self:
Rc
Arc
Pin
This means that the original example now works:
use std::{rc::Rc, sync::Arc};
struct Bar;
impl Bar {
fn consuming(self) { println!("self") }
fn reference(&self) { println!("&self") }
fn mut_reference(&mut self) { println!("&mut self") }
fn boxed(self: Box<Bar>) { println!("Box") }
fn ref_count(self: Rc<Bar>) { println!("Rc") }
fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}
fn main() {
Bar.consuming();
Bar.reference();
Bar.mut_reference();
Box::new(Bar).boxed();
Rc::new(Bar).ref_count();
Arc::new(Bar).atomic_ref_count();
}
However, the impl handling hasn't yet been fully generalised to match the syntax, so user-created types still don't work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.
(Something to look forward to!)
It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:
#![feature(arbitrary_self_types)]
Using feature crate attributes requires using nightly Rust.

Resources