cannot use `*self` because it was mutably borrowed - rust

I'm running into this issue. My code looks like this:
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob";
self.bar(self, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: String) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
However, I'm getting this error error: mismatched types: expected 'MyStruct', found '&mut MyStruct' (expected struct MyStruct, found &-ptr) in my foo method. I understand that Rust has not yet reached its 1.0 release but I'd like to understand pointers in Rust.
What am I doing wrong and what are some other ways to fix it?
What I've tried:
let f = *self;
self.bar(f, "Foo"); // works using the "raw pointer"
self.bar(*self, "Foo"); // doesn't work.. Error message: "borrow of `*self` occurs here"
rust version: rustc 0.12.0-pre-nightly (09abbbdaf 2014-09-11 00:05:41 +0000)

First of all, literals like "Foo" are not Strings, they are &'static strs. The difference is, String is an actual allocated buffer containing string contents and &str is just a view into existing buffer. &'static strs are, therefore, views into some statically allocated data. You can't pass &str as a String, so your example should look something like this:
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
self.bar(self, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
However, this doesn't work, as you have already noticed, and won't even after the String -> &str change:
self.bar(self, "Foo")
Neither will this:
self.bar(*self, "Foo")
nor this:
let f = *self; // this is not a "raw pointer", BTW, this is just a dereference
self.bar(f, "Foo")
The first variant won't work simply because the types do not match: self is &mut MyStruct, and bar() expects plain MyStruct as the first argument.
The second and the third variants are basically equivalent and could in fact work if MyStruct was a Copy type (if it implemented Copy trait). It isn't, however, because it contains String, which is not a Copy type since it has an associated destructor. Because of this the compiler does not implement Copy for MyStruct, and values of such types can only be moved around, not copied.
But you can't move a value out of &mut reference because a reference is a non-owning view of data, so *self just won't compile.
Moreover, there is a further obstacle. Because you want to pass self into bar() somehow, you can't do it using references, which would be the best choice otherwise. That is, this won't work:
fn bar(&mut self, my_struct: &MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name);
}
self.bar(self, "Foo"); // self as an argument is auto-reborrowed from &mut to &
This happens because Rust does not allow having &mut reference into some data at the same time with any other reference to the same data, and this is exactly what would happen here: self.bar(self, "Foo") method call requires &mut MyStruct as its target but also &MyStruct as its argument, and because self is passed as both of them, the compiler would reject it.
Hence if you want to keep the code as close as possible to your original intent, your best bet would be using Clone. Derive Clone for your structure:
#[deriving(Clone)]
struct MyStruct {
name: String
}
Then you can use clone() method to obtain a copy of your structure:
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
let c = self.clone();
self.bar(c, "Foo");
}
fn bar(&mut self, my_struct: MyStruct, last_name: &str) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}
However, it is possible that your code needs restructuring. Often such things could be expressed more clearly, for example, by moving bar() call up to foo() caller.
I highly recommend reading the official Rust guide which explains such concepts as ownership, borrowing and references. After that the reason why your code does not work should be more clear.

You have two problems in your code.
The first is a minor problem with your strings. When you type "Bob", it has type &'static str, while you want String in at least some of the places in your code. This is easily fixed by replacing "Bob" with "Bob".to_string().
The second problem is that, you are essentially trying to give the same value to the function twice. You can do that in rust, but you need to be very careful about how you do it.
The easiest way to fix, would be to clone the object, thus giving two different (but equal) objects. Your example in this case would be:
#[deriving(Clone)]
struct MyStruct {
name:String
}
impl MyStruct {
fn foo(&mut self) {
self.name = "Bob".to_string();
let cloned = self.clone();
self.bar(clone, "Foo".to_string());
}
fn bar(&mut self, my_struct: MyStruct, last_name: String) {
self.name = format!("{} {}", my_struct.name, last_name)
}
}

Related

How can I mutate fields of a struct while referencing other fields?

Here's an example of a problem I ran into:
pub struct Item {
name: String,
value: LockableValue, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&mut self) -> &mut LockableValue {
&self.value
}
}
pub fn update(item: &mut Item) {
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", item.name());
}
Now, I know why this fails. I have a mutable reference to item through the mutable reference to the value.
If I convert the reference to an owned String, it works fine, but looks strange to me:
pub fn update(item: &mut Item) {
let name = { item.name().to_owned() };
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name); // It works!
}
If I let value reference drop, then everything is fine.
pub fn update(item: &mut Item) {
{
let value = item.value_mut();
value.change(); // how it changes is unimportant
}
println!("Updated item: {}", item.name()); // It works!
}
The value.change() block is rather large, and accessing other fields in item might be helpful. So while I do have solutions to this issue, I'm wondering if there is a better (code-smell) way to do this. Any suggestions?
My intention behind the above structs was to allow Items to change values, but the name should be immutable. LockableValue is an tool to interface with another memory system, and copying/cloning the struct is not a good idea, as the memory is managed there. (I implement Drop on LockableValue to clean up.)
I was hoping it would be straight-forward to protect members of the struct from modification (even if it were immutable) like this... and I can, but it ends up looking weird to me. Maybe I just need to get used to it?
You could use interior mutability on only the part that you want to mutate by using a RefCell like ths:
use std::cell::{RefCell, RefMut};
pub struct LockableValue;
impl LockableValue {
fn change(&mut self) {}
}
pub struct Item {
name: String,
value: RefCell<LockableValue>, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&self) -> RefMut<'_, LockableValue> {
self.value.borrow_mut()
}
}
pub fn update(item: &Item) {
let name = item.name();
let mut value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name);
}
That way you only need a shared reference to Item and you don't run into an issue with the borrow checker.
Not that this forces the borrow checks on value to be done at runtime though and thus comes with a performance hit.

Borrow Checker Not Releasing Immutable Borrow

I'm having a problem in the code below where the borrow checker complains about an immutable borrow in the call to self.entries.push() despite placing all the temporary code inside its own scope.
I have checked other posts with similar problems, but I can't figure out how to adapt the code to my own situation -- I'm still pretty new to Rust. Suggestions?
impl Entry {
pub fn chain(&self, spair: &SigningPair, expires: u16)
-> Result<(Entry, HashMap<&str,CryptoString>), MensagoError> {
// New Entry and HashMap allocated in here to be returned
}
}
pub struct Keycard {
_type: EntryType,
pub entries: Vec<Entry>,
}
impl Keycard {
pub fn get_current(&self) -> Option<&Entry> {
// ...
}
pub fn chain(&mut self, spair: &SigningPair, expires: u16)
-> Result<HashMap<&str,CryptoString>, MensagoError> {
let (newentry, keys) = {
let entry = match self.get_current() {
Some(v) => v,
None => { return Err(MensagoError::ErrEmptyData) }
};
match entry.get_field("Type")?.as_str() {
"Organization" | "User" => (),
_ => { return Err(MensagoError::ErrInvalidKeycard) }
}
entry.chain(spair, expires)?
};
self.entries.push(newentry);
Ok(keys)
}
}
I'm fairly certain that the error is because the returnvalue of chain() is incorrect:
HashMap<&str,CryptoString> should be HashMap<&'static str,CryptoString> or HashMap<String,CryptoString>
The explanation is a little bit longer, though.
Rust borrow checker demands that a value can be:
borrowed immutably by many borrowers or
borrowed mutably by exactly one borrower
no other borrows can exist (mutable or immutable) when a value gets modified
You try to modify the value self.entry at self.entries.push(newentry). Therefore, there must not be any borrows that reference self.entry.
Sadly, a borrow chain exists that borrows self, which indirectly also borrows self.entry at that point in time:
the type of newentry contains a reference, &str. newentry got created in .chain(), where &str has no lifetime annotations and therefore has the same lifetime as entry.
entry is created by self.get_current(), where again, &Entry is a reference with no explicit lifetime annotation and therefore has the same lifetime as self.
Which means through the chain newentry -> entry -> self, the self object is still borrowed while you try to call self.entries.push(). This is exactly what the error message is trying to tell you.
There are several solutions to those problems usually:
Introduce Rc instead of references
.clone() somewhere in between to break the reference chain
make sure that the reference chain actually makes sense in the first place, and if not, introduce lifetimes appropriately
In your case I think it's solution #3, as there is no reason why newentry should borrow entry. The type &str is most likely incorrect and should be &'static str. In my experience, using &str as a key for HashMap doesn't make much sense, it should be either &'static str (= global constant string like "hello") or the owned, mutable version String. Using a temporary reference as a key is quite strange and therefore most likely a beginner error.
The fixed version is:
use std::collections::HashMap;
pub struct Entry;
pub struct SigningPair;
pub struct CryptoString;
pub enum MensagoError {
ErrEmptyData,
ErrInvalidKeycard,
}
pub struct EntryType;
impl Entry {
pub fn chain(
&self,
_: &SigningPair,
_: u16,
) -> Result<(Entry, HashMap<&'static str, CryptoString>), MensagoError> {
todo!()
}
fn get_field(&self, _: &str) -> Result<String, MensagoError> {
todo!()
}
}
pub struct Keycard {
_type: EntryType,
pub entries: Vec<Entry>,
}
impl Keycard {
pub fn get_current(&self) -> Option<&Entry> {
todo!()
}
pub fn chain(
&mut self,
spair: &SigningPair,
expires: u16,
) -> Result<HashMap<&str, CryptoString>, MensagoError> {
let (newentry, keys) = {
let entry = match self.get_current() {
Some(v) => v,
None => return Err(MensagoError::ErrEmptyData),
};
match entry.get_field("Type")?.as_str() {
"Organization" | "User" => (),
_ => return Err(MensagoError::ErrInvalidKeycard),
}
entry.chain(spair, expires)?
};
self.entries.push(newentry);
Ok(keys)
}
}

Why RefCell's `into_inner` requires a move?

I have a situation where I have to move a struct from one object to another through a &mut self. Take a look:
pub struct MyStruct {
//no copy trait
device: Device
}
impl MyStruct {
pub fn finalize(&mut self) {
//error: cannot move since I borrowed
let interface = InterfaceBuilder::new(self.device)
}
}
First of all, why I cannot move something out of a borrowed mutable reference? Borrowed mutables are exclusive, there's no chance another code is looking into it.
Well, to address this problem I changed to
pub struct MyStruct {
//no copy trait
device: RefCell<Device>
}
impl MyStruct {
pub fn finalize(&mut self) {
//error on `self.device`: cannot move out of `self.device` which is behind a mutable reference
let interface = InterfaceBuilder::new(self.device.into_inner())
}
}
I know why the error occurs:
pub fn into_inner(self) -> T
calling into_inner makes self.device move. Why RefCell simply does not have an implementation pub fn into_inner(&mut self) -> T? I don't see a problem.
You cannot move out of a mutable reference because that would leave the original object incomplete.
Consider this code:
struct MyStruct {
s: String
}
fn finalize(f: &mut MyStruct) {
let _x = f.s; //error E0507!
}
fn main() {
let mut my = MyStruct {
s: "hi".into()
};
finalize(&mut my);
println!("{}", my.s); //what should this do?
}
Then, RefCell::into_inner(&mut self) -> T has the same problem. You could call it twice in a row and you would get two T values where before there was only one. And that, for a non Copy type is impossible.
If you want this function to consume the inner value, probably it should consume the outer value too:
fn finalize(f: MyStruct) {
let _x = f.s;
}
If you really want to move a value out of a mutable reference, you must leave something valid in its place. The easiest way is to declare an Option and use take() to steal and replace it with a None:
struct MyStruct {
s: Option<String>
}
fn finalize(f: &mut MyStruct) {
let _x = f.s.take();
}
Naturally, Option::take returns an Option so that if you call it twice, the second time you get None. If you are positive you have a value you can do take().uwnrap().
Alternatively, if your field type is Default you can use std::mem::take that replaces it with a default-created value:
struct MyStruct {
s: Vec<i32>
}
fn finalize(f: &mut MyStruct) {
let _x = std::mem::take(&mut f.s);
}
PS #1: there is Cell::take(&self) -> T, but only if T implements Default. It works just like std::mem::take but with a non-mutable reference.
PS #2: there is also unsafe fn ManuallyDrop::take(slot: &mut ManuallyDrop<T>) -> T, that is intented to be used in advanced drop implementations. But it is unsafe so it should never be your first option: if you call it twice you will get undefined behavior.

Lifetime error for returned value of a function

This is a simplified version of a piece of code I am trying to implement:
struct FirstStruct
{
a: i8,
}
impl FirstStruct
{
fn get(&self) -> Option<&str>
{
Some("aaa")
}
}
pub struct SecondStruct<'a>
{
pub name: Option<&'a str>,
}
impl<'a> SecondStruct<'a>
{
fn extract_string(obj: &/*'a*/ FirstStruct) -> Option<&'a str>
{
obj.get() //this is where the error happen
}
pub fn from_string() -> SecondStruct<'a>
{
let obj = FirstStruct{a: 1};
SecondStruct{
name: SecondStruct::extract_string(&obj),
}
}
}
fn main()
{
let g_def_res = SecondStruct::from_string();
}
This code throws the following error :
test2.rs:23:13: 23:18 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
test2.rs:23 obj.get() //this is where the error happen
^~~~~
test2.rs:21:5: 24:6 help: consider using an explicit lifetime parameter as shown: fn extract_string(obj: &'a FirstStruct) -> Option<&'a str>
test2.rs:21 fn extract_string(obj: &FirstStruct) -> Option<&'a str>
test2.rs:22 {
test2.rs:23 obj.get() //this is where the error happen
test2.rs:24 }
error: aborting due to previous error
Applying the proposed solution throw this error :
test2.rs:30:55: 30:58 error: `obj` does not live long enough
test2.rs:30 name: SecondStruct::extract_string(&obj),
^~~
test2.rs:27:5: 32:6 note: reference must be valid for the lifetime 'a as defined on the block at 27:4...
test2.rs:27 {
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
test2.rs:28:37: 32:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 28:36
test2.rs:28 let obj = FirstStruct{a: 1};
test2.rs:29 SecondStruct{
test2.rs:30 name: SecondStruct::extract_string(&obj),
test2.rs:31 }
test2.rs:32 }
error: aborting due to previous error
To summarise:
How to say that the return value of FirstStruct::get must have the lifetime of either [the return value of SecondStruct::from_str | the struct lifetime 'a]? I think both refer to same thing?
pub fn from_string() -> SecondStruct<'a> {
let obj = FirstStruct { a: 1 };
SecondStruct {
name: SecondStruct::extract_string(&obj),
}
}
This code says "I will return a SecondStruct with the lifetime 'a". The caller of the code gets to determine what the length of the lifetime 'a is. This is almost never what you want!
// Lifetime elision means the method is equivalent to this
// fn get<'a>(&'a self) -> Option<&'a str>
fn get(&self) -> Option<&str> {
Some("aaa")
}
This code uses says that the string returned will live as long as self lives.
Put these two concepts together, and you can understand your error. The variable obj is only defined to live as long as the function call is active. However, you are trying to return a reference to the inner-workings of the struct beyond the call! Actually, you are trying to return it for any arbitrary lifetime the caller decides! This is Rust preventing you from shooting yourself in the foot, hooray for Rust!
So how do you fix your problem? For the provided example code, the easiest thing is to just use the 'static lifetime:
struct FirstStruct { a: i8 }
impl FirstStruct {
fn get(&self) -> Option<&'static str> { Some("aaa") }
}
pub struct SecondStruct<'a> { name: Option<&'a str> }
impl<'a> SecondStruct<'a> {
fn extract_string(obj: &FirstStruct) -> Option<&'static str> { obj.get() }
pub fn from_string() -> SecondStruct<'static> {
let obj = FirstStruct { a: 1 };
SecondStruct { name: SecondStruct::extract_string(&obj) }
}
}
fn main() {
let g_def_res = SecondStruct::from_string();
}
But that's probably not what you really want. The next thing to try would be to embed FirstStruct inside SecondStruct, and simply delegate to it. Another option would be to move from &str to String - String owns the string data, and so you can transfer ownership from First to Second.
Whatever you do, you have to ensure that the source of the string data outlives the function call to from_string.
Either the return value of FirstStruct::get has been allocated on the stack or it has been allocated on the heap.
It's trickier than that. The return value is always on the stack. That is, the Option<&str> takes up space on the stack. The &str may contain a pointer to something that is allocated either on the stack or heap, it's not known by this code. All you know is that the pointed-at value is guaranteed to live for the lifetime of that specific FirstStruct item.
You don't own the string, so you can't transfer ownership around.
I can't move FirstStruct because it is from another library (rustc-serialize
I'm not sure what you mean. If you have an object, then you can embed it into your object. The fact that it comes from another crate doesn't come into play. If you have a reference to something, then you can still capture the reference, but then your object has to live for a shorter period than the reference (so that it never becomes invalid).
Unwrapping Option, updating to a string and rewrapping in Option is a lot of boilerplate.
Have you seen Option::map? It makes this kind of thing very succinct. Combined with From, you can write a very short thing to convert an Option<&str> to Option<String>:
// fn is just to establish some types, you'd just use the `.map` call in real code
fn foo(a: Option<&str>) -> Option<String> {
a.map(From::from)
}

Returning a string from a method in Rust

Editor's note: The syntax in this question predates Rust 1.0 and the 1.0-updated syntax generates different errors, but the overall concepts are still the same in Rust 1.0.
I have a struct T with a name field, I'd like to return that string from the name function. I don't want to copy the whole string, just the pointer:
struct T {
name: ~str,
}
impl Node for T {
fn name(&self) -> &str { self.name }
// this doesn't work either (lifetime error)
// fn name(&self) -> &str { let s: &str = self.name; s }
}
trait Node {
fn name(&self) -> &str;
}
Why is this wrong? What is the best way to return an &str from a function?
You have to take a reference to self.name and ensure that the lifetimes of &self and &str are the same:
struct T {
name: String,
}
impl Node for T {
fn name<'a>(&'a self) -> &'a str {
&self.name
}
}
trait Node {
fn name(&self) -> &str;
}
You can also use lifetime elision, as shown in the trait definition. In this case, it automatically ties together the lifetimes of self and the returned &str.
Take a look at these book chapters:
References and borrowing
Lifetime syntax

Resources