Rust - Lifetime of struct member depends on another struct member [duplicate] - rust

This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 3 years ago.
I'm trying to write a Rust struct. The struct owns a Reference counted pointer to a string and also owns a vector of string slices to the same string.
Furthermore I'm trying to write a function to generate this struct. I'm unsure how to proceed.
struct MyStruct<'a> {
rc_string: Rc<String>,
vec: Vec<&'a str>
}
fn build_my_struct<'a>(s: &Rc<String>) -> MyStruct<'a> {
let rc_string = s.clone();
let mut vec = Vec::new();
vec.push(&rc_string[0..2]);
MyStruct {
rc_string: rc_string,
vec: vec
}
}
error[E0515]: cannot return value referencing local variable `rc_string`
--> src/main.rs:13:5
|
11 | vec.push(&rc_string[0..2]);
| --------- `rc_string` is borrowed here
12 |
13 | / MyStruct {
14 | | rc_string: rc_string,
15 | | vec: vec
16 | | }
| |_____^ returns a value referencing data owned by the current function
I understand that the vec variable has borrowed the rc_string. The compiler doesn't like returning vec because it has the borrow to the local variable rc_string.
However rc_string is being returned as well? The string slices are valid for the duration of the life of MyStruct.rc_string?

You need to borrow Rc for life time 'a as well. Compiler needs to know that slice from a String is living in 'a or not. In this case we need to borrow Rc for 'a and compiler will know inner of Rc will also live in 'a.
If you clone s and assign it to rc_string:
s will stay in the function's scope as borrowed Rc for lifetime 'a
rc_string will be the owner of the Rc pointer
and compiler won't be able to know slice of a rc_string is living for 'a or not.
Using slice from a s will work :
fn build_my_struct<'a>(s: &'a Rc<String>) -> MyStruct<'a> {
let mut vec = Vec::new();
let rc_string = s.clone();
vec.push(&s[0..2]);
MyStruct { rc_string, vec }
}
Playground

Related

Why can I not mutably borrow separate fields from a mutex guard? [duplicate]

This question already has an answer here:
Error while trying to borrow 2 fields from a struct wrapped in RefCell
(1 answer)
Closed 3 years ago.
Trying to get mutable references to separate fields through a MutexGuard:
struct MyObject {
pub a: i32,
pub b: i32,
}
fn func_1(mtx: &Mutex<MyObject>) {
let mut obj = mtx.lock().unwrap();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
results in an error:
error[E0499]: cannot borrow `obj` as mutable more than once at a time
--> src/main.rs:11:18
|
10 | let a = &mut obj.a;
| --- first mutable borrow occurs here
11 | let b = &mut obj.b;
| ^^^ second mutable borrow occurs here
12 |
13 | *a += 1;
| ------- first borrow later used here
This has me a bit confused. This works when obj is a simple mutable reference (&mut MyObject). I thought maybe the Deref trait was the one causing the problem, but it also works if obj is a &mut Box<MyObject>.
See it on the Rust Playground.
What am I missing?
Mutex::lock returns a RAII lock guard in addition of ways to deal with its contained value. To get its contained value as &mut (and subsequently "split borrow"), you need to:
save the guard (returned by lock) in a separate value, as the lock needs to live as long as the value is accessed.
extract the value as &mut from the guard with MutexGuard::deref_mut.
Here's an updated func_1:
use std::ops::DerefMut;
fn func_1(mtx: &Mutex<MyObject>) {
let mut guard = mtx.lock().unwrap();
let obj = guard.deref_mut();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}

Cannot use the entry API to mutate a HashMap using a reference as the key inside of a function

I'm trying to get a handle to an element in a mutable HashMap reference where the keys are &str.
In the example below, I'm trying to get value dict[key] so I can mutate it. How do I do this?
I've tried:
dict.entry(key): lifetime mismatch
dict.entry(&String::from(key)): borrowed value does not live long enough
e.g. this:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
let num = dict.entry(&String::from(key)).or_insert(0);
*num += 1;
return 42;
}
Errors out with:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:4:27
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| - let's call the lifetime of this reference `'1`
4 | let num = dict.entry(&String::from(key)).or_insert(0);
| ------------^^^^^^^^^^^^^^^^^- - temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'1`
Link the lifetime of the key argument to the lifetime of the keys in the HashMap:
use std::collections::HashMap;
fn do_thing<'a>(key: &'a str, dict: &mut HashMap<&'a str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
dict.entry(key)
The error message for this version helps understand the problem:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
error[E0623]: lifetime mismatch
--> src/lib.rs:4:17
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| ---- ----
| |
| these two types are declared with different lifetimes...
4 | *dict.entry(key).or_insert(0) += 1;
| ^^^ ...but data from `key` flows into `dict` here
Specifically, entry will store key in the HashMap, but the value referenced by key might become invalid before the HashMap does. If that happened, the HashMap would contain a dangling reference, pointing to invalid memory. That's exactly what Rust's borrow checker prevents.
See also:
When is it required to use lifetimes?
Why are explicit lifetimes needed in Rust?
dict.entry(&String::from(key))
This can never work here, for much the same reason.
See also:
Return local String as a slice (&str)

Why can't I call a mutating function more than once? [duplicate]

This question already has answers here:
Cannot borrow `x` as mutable more than once at a time
(2 answers)
Cannot borrow as mutable more than once at a time in one code - but can in another very similar
(2 answers)
What is the difference between '&self' and '&'a self'?
(1 answer)
Closed 3 years ago.
This is based on my previous question.
I have code that is failing with borrow checker error and I reduced it as much as I could. This is the result:
struct MyStruct<'a> {
s: &'a str,
}
impl<'a> MyStruct<'a> {
fn foo(&'a mut self) {}
}
fn main() {
let mut m = MyStruct { s: "aaa" };
m.foo();
m.foo();
}
It is failing with:
error[E0499]: cannot borrow `m` as mutable more than once at a time
--> src/main-x.rs:13:5
|
12 | m.foo();
| - first mutable borrow occurs here
13 | m.foo();
| ^
| |
| second mutable borrow occurs here
| first borrow later used here
The code was reduced so much that it does nothing useful and could be fixed for example by removing the 'a lifetime from the foo function. But I would like to understand why is the code not ok as it is.
My understanding is that MyStruct contains reference to str of some lifetime 'a and foo can be called with self pointing to MyStruct of the same lifetime. I don't see why is m considered mutably borrowed after the first call to foo.
When you declare foo as
fn foo(&'a mut self) {}
you say the mutable borrow of self has the same lifetime 'a as the embedded string. So it stays borrowed as long as the struct lives. Calling foo is like definitely giving away the ownership of the struct.
You can fix it by declaring foo as
fn foo(&mut self) {}

What is the correct way to get values via a method without moving it? [duplicate]

This question already has answers here:
How to prevent a value from being moved?
(2 answers)
When would an implementation want to take ownership of self in Rust?
(2 answers)
What do I have to do to solve a "use of moved value" error?
(3 answers)
How can I solve "use of moved value" and "which does not implement the `Copy` trait"?
(1 answer)
Closed 3 years ago.
I don't understand why Rust moves the value. Do I oversee a major point in the ownership?
The struct MyData is a smaller version. I store some values in this struct, and want to access the stored values, but the compiler tells me after the second access, that the value was moved.
I want to make some getters for my structs. I already derived Clone, but that does not help.
The problem occurs on Windows 10 with the GNU-Compiler and on Kubuntu 18.04 LTS.
My current workaround is to clone the data beforehand, but this can't be the correct way.
#[derive(Debug, Clone)]
struct MyData {
val1: i32,
val2: String,
}
impl MyData {
pub fn get_val1(self) -> i32 {
return self.val1.clone();
}
pub fn get_val2(self) -> String {
return self.val2.clone();
}
pub fn get_both(self) -> (i32, String) {
return (self.val1, self.val2);
}
}
fn main() {
let d = MyData {
val1: 35,
val2: String::from("Hello World"),
};
let both = d.get_both();
let x = d.get_val1();
let y = d.get_val2();
}
error[E0382]: use of moved value: `d`
--> src/main.rs:28:13
|
27 | let both = d.get_both();
| - value moved here
28 | let x = d.get_val1();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `d`
--> src/main.rs:29:13
|
28 | let x = d.get_val1();
| - value moved here
29 | let y = d.get_val2();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
I expect that let x = d.get_val1(); won't cause an error. In my understanding of ownership in Rust, I did not move the value, since I'm calling a method of MyData and want to work with the value.
Why does Rust move the value and to whom?

Borrowed value does not live long enough when creating a Vec

Editor's note: This question was asked before Rust 1.0. Since then, many functions and types have changed, as have certain language semantics. The code in the question is no longer valid, but the ideas expressed in the answers may be.
I'm trying to list the files in a directory and copy the filename to my own Vec. I've tried several solutions, but it always ends up with a problem of not being able to create long enough living variables. I don't understand my mistake.
fn getList(action_dir_path : &str) -> Vec<&str> {
let v = fs::readdir(&Path::new(action_dir_path))
.unwrap()
.iter()
.map(|&x| x.filestem_str().unwrap())
.collect();
return v;
}
Why does the compiler complain about "x" ? I don't care about x, I want the &str inside it and I thought &str were static.
I tried this way, but I got the same result with the compiler complaining about "paths" not living long enough.
fn getList2(action_dir_path : &str) -> Vec<&str> {
let paths = fs::readdir(&Path::new(action_dir_path)).unwrap();
let mut v : Vec<&str> = Vec::new();
for path in paths.iter(){
let aSlice = path.filestem_str().unwrap();
v.push(aSlice);
}
return v;
}
Here is the playground.
The most literal translation of your code that supports Rust 1.0 is this:
use std::{fs, path::Path, ffi::OsStr};
fn getList(action_dir_path: &str) -> Vec<&OsStr> {
let v = fs::read_dir(&Path::new(action_dir_path))
.unwrap()
.map(|x| x.unwrap().path().file_stem().unwrap())
.collect();
return v;
}
This produces the error messages:
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:6:18
|
6 | .map(|x| x.unwrap().path().file_stem().unwrap())
| ^^^^^^^^^^^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 3:1...
--> src/lib.rs:3:1
|
3 | / fn getList(action_dir_path: &str) -> Vec<&OsStr> {
4 | | let v = fs::read_dir(&Path::new(action_dir_path))
5 | | .unwrap()
6 | | .map(|x| x.unwrap().path().file_stem().unwrap())
7 | | .collect();
8 | | return v;
9 | | }
| |_^
Rust 2018
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:6:18
|
6 | .map(|x| x.unwrap().path().file_stem().unwrap())
| -----------------^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
The problem comes from Path::file_stem. This is the signature:
pub fn file_stem(&self) -> Option<&OsStr>
This indicates that the method will return a borrowed reference to a OsStr. The PathBuf struct is the owner of the string. When you leave the method, there's nowhere left that owns the PathBuf, so it will be dropped. This means that any references into the PathBuf will no longer be valid. This is Rust preventing you from having references to memory that is no longer allocated, yay for Rust!
The easiest thing you can do is return a Vec<String>. String owns the string inside of it, so we don't need to worry about it being freed when we leave the function:
fn get_list(action_dir_path: &str) -> Vec<String> {
fs::read_dir(action_dir_path)
.unwrap()
.map(|x| {
x.unwrap()
.path()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string()
})
.collect()
}
I also updated the style (at no charge!) to be more Rust-like:
Use snake_case for items
No space before the colon in type definitions
There's no reason to set a variable just to return it.
Don't use explicit return statements unless you are exiting from a function early.
There's no need to wrap the path in a Path.
However, I'm not a fan of all of the unwrapping. I'd write the function like this:
use std::{ffi::OsString, fs, io, path::Path};
fn get_list(action_dir_path: impl AsRef<Path>) -> io::Result<Vec<OsString>> {
fs::read_dir(action_dir_path)?
.map(|entry| entry.map(|e| e.file_name()))
.collect()
}
fn main() {
println!("{:?}", get_list("/etc"));
}
In addition to the changes above:
I use a generic type for the input path.
I return a Result to propagate errors to the caller.
I directly ask the DirEntry for the filename.
I leave the type as an OsString.
One small related point:
I thought &str were static.
&'static strs are static, but that's only one kind of &str. It can have any kind of lifetime.

Resources