rust: expected lifetime parameter problem [duplicate] - rust

This question already has answers here:
How to return new data from a function as a reference without borrow checker issues?
(1 answer)
Return local String as a slice (&str)
(7 answers)
Closed 3 years ago.
I am new to Rust and was making a simple program to practice which takes 2 numbers and prints the numbers between them. This is my code
fn main() {
let a: u32 = 2;
let b: u32 = 10;
let a = result(&a, &b);
println!("{:?}", a);
}
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
let mut vec = Vec::new();
for x in a..b {
vec.push(a);
}
vec
}
When i run this program, i get this error
fn result(a: &u32, b: &u32) -> [Vec<&u32>] {
| ^ expected lifetime parameter
The concepts of borrowing and lifetimes are still very new and strange to me. Please help me in determining where i am wrong.

The error message is quite clear here:
this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from a or b
Providing an explicit lifetime would help the compiler understand what you're trying to do:
fn result<'a>(a: &'a u32, b: &'a u32) -> Vec<&'a u32> {
let mut vec: Vec<&'a u32> = Vec::new();
for x in *a..*b {
vec.push(&x);
}
vec
}
But the above wouldn't work either, as borrowing x results in borrowing a variable whch only lives in the scope a single iteration:
vec.push(&x);
^^ borrowed value does not live long enough
What you probably want is to avoid borrowing altogether:
fn result(a: u32, b: u32) -> Vec<u32> {
let mut vec = Vec::new();
for x in a..b {
vec.push(x);
}
vec
}
live example on godbolt.org

Related

rust initializing a String field in a struct with a String that belongs to a HashMap in the same structure [duplicate]

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 1 year ago.
I have read those two similar questions here and here. But still can't figure out how to achieve what I want: initializing a String field in a struct with a String that belongs to a HashMap in the same structure. Here is my initial code:
use std::collections::HashMap;
struct S<'a> {
a: HashMap<String,Vec<String>>,
b: &'a String,
}
impl <'a> S<'a> {
fn new() -> S<'a> {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = &h.get("toto").unwrap()[0];
S {
a: h, // error[E0505]: cannot move out of `h` because it is borrowed
b: b // error[E0515]: cannot return value referencing local variable `h`
}
}
}
fn main() {
let mut s = S::new();
println!("s.b = {}", s.b);
}
I would like b to be initilaized with a String value that belong to the HashMap a. Since the above did not work, I tried to initialize b with an empty String, and immediatly change b's value after creating s:
use std::collections::HashMap;
struct S {
a: HashMap<String,Vec<String>>,
b: String,
}
impl S {
fn new() -> S {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = "".to_string();
S {
a: h,
b: b
}
}
}
fn main() {
let mut s = S::new();
s.b = s.a.get("toto").unwrap()[0]; //error[E0507]: cannot move out of index of `Vec<String>`
println!("s.b = {}", s.b);
}
Since I cannot copy the value into s.b:
error[E0507]: cannot move out of index of `Vec<String>`
--> src/main.rs:24:15
|
24 | s.b = s.a.get("toto").unwrap()[0]; //error[E0507]: cannot move out of index of `Vec<String>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
I thought that a reference could work:
use std::collections::HashMap;
struct S<'a> {
a: HashMap<String,Vec<String>>,
b: &'a String,
}
impl <'a> S<'a> {
fn new() -> S<'a> {
let mut v:Vec<String> = Vec::new();
v.push("a".to_string());
v.push("b".to_string());
let mut h = HashMap::new();
h.insert("toto".to_string(),v);
let b = &"".to_string();
S {
a: h,
b: b // error[E0515]: cannot return value referencing temporary value
}
}
}
fn main() {
let mut s = S::new();
s.b = &s.a.get("toto").unwrap()[0];
println!("s.b = {}", s.b);
}
But of course, I run into the same issue of referencing a value that does not have a lifetime longer than the function. No clue how/if I can tell the compiler that my empty String should live as long as S.
There might be an obvious solution, but if so, I can't see it :-(
There might be an obvious solution, but if so, I can't see it :-(
If your goal is to share the value between the map and the field, then no. Rust does not like self-referential data structures.
And a string is affine, you can't have both the structure and the nested map own the "same" string unless:
you relax the ownership using Rc or Arc
you clone() the string and both just have a copy of the same thing
There are also crates for string caching / interning, but I've no idea how convenient & efficient they are.

Does a mutable String reference implement Copy [duplicate]

This question already has answers here:
Why is the mutable reference not moved here?
(4 answers)
Do mutable references have move semantics?
(1 answer)
Closed 1 year ago.
In the below code I was expecting the compiler to complain about use of moved value: xref on hello function's second call since mutable references do not implement Copy. The compiler doesn't raise any such error. What am I missing here?
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref);
hello(x_ref);
}
fn hello(a: &mut String) {
println!("Hello {}", a);
}
Your example uses the mutable references after each other, which allows the compiler to perform an implicit reborrow. It basically turns this code into this:
hello(&mut *x_ref);
hello(&mut *x_ref);
Now you have two separate mutable borrows each only for the lifetime of the function call, thus they do not conflict with each other.
You see an error if you try to use it two times simultaneously.
fn main() {
let mut x: String = "Developer".to_string();
let x_ref: &mut String = &mut x;
hello(x_ref, x_ref);
}
fn hello(a: &mut String, b: &mut String) {
println!("Hello {} and {}", a, b);
}

How do I implement a newtype wrapper around borrowed values? [duplicate]

This question already has answers here:
How to wrap a borrowed value in a newtype that is also a borrowed value?
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 2 years ago.
I'm trying to implement a newtype wrapper around a borrowed value, in order to implement different behavior for a trait but can't get this to conform to the borrowing rules. I prepared a simplified example below.
Note: The actual code is more complex and also needs to work with values that need .as_any().downcast_ref() first, which is why I'd like this to work with borrowed values.
use std::cmp::Ordering;
trait OrdVec {
fn cmp(&self, i: usize, j: usize) -> Ordering;
}
// note: actual trait bound is more complex and would lead to
// "conflicting implementations" when trying to implement `OrdSlice for &[f64]`
impl<T> OrdVec for Vec<T>
where
T: Ord,
{
fn cmp(&self, i: usize, j: usize) -> Ordering {
self[i].cmp(&self[j])
}
}
#[repr(transparent)]
struct F64VecAsOrdVec<'a>(&'a Vec<f64>);
impl OrdVec for F64VecAsOrdVec<'_> {
fn cmp(&self, i: usize, j: usize) -> Ordering {
let a: f64 = self.0[i];
let b: f64 = self.0[j];
if a < b {
return Ordering::Less;
}
if a > b {
return Ordering::Greater;
}
unimplemented!("convert NaN to canonical form and compare bitwise")
}
}
fn as_ord_vec<'a>(first: bool, int_vec: &'a Vec<i64>, float_vec: &'a Vec<f64>) -> &'a dyn OrdVec {
if first {
int_vec
} else {
// returns a reference to data owned by the current function
&F64VecAsOrdVec(float_vec)
// newtype should have same layout but this fails on calling `cmp`
// with "SIGSEGV: invalid memory reference"
// let ord: &F64VecAsOrdVec = unsafe { std::mem::transmute(float_vec) };
// ord
}
}
#[test]
fn test_int_as_ord() {
let int_vec = vec![1, 2, 3];
let float_vec = vec![3.0, 2.0, 1.0];
let int_ord = as_ord_vec(true, &int_vec, &float_vec);
assert_eq!(Ordering::Less, int_ord.cmp(0, 1));
}
#[test]
fn test_float_as_ord() {
let int_vec = vec![1, 2, 3];
let float_vec = vec![3.0, 2.0, 1.0];
let float_ord = as_ord_vec(false, &int_vec, &float_vec);
assert_eq!(Ordering::Greater, float_ord.cmp(0, 1));
}
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:43:5
|
43 | &F64VecAsOrdVec(vec)
| ^-------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function

Cannot build equivalent closure for a function when the closure contains complex lifetime relationships [duplicate]

This question already has answers here:
How to declare a higher-ranked lifetime for a closure argument?
(3 answers)
Closed 3 years ago.
I've got some trouble with replacing function with equivalent closure, compiler complaining
cannot infer an appropriate lifetime due to conflicting requirements
note: ...so that the types are compatible:
expected &std::collections::BTreeSet<&str>
found &std::collections::BTreeSet<&str> rustc(E0495)
in the closure, at the rangemethod in r.extend(s.range(lower..=upper));.
But i can't figure out how to put lifetime hint in a closure, and maybe, it's not possible.
use std::collections::BTreeSet;
fn main() {
let mut set = BTreeSet::new();
set.insert("TEST1");
set.insert("TEST3");
set.insert("TEST4");
set.insert("TEST2");
set.insert("TEST5");
println!("init: {:?}", set);
let closure = |lower, upper| {
|s: &BTreeSet<&str>| {
let mut r = BTreeSet::new();
r.extend(s.range(lower..=upper));
r
}
};
set = extract_fn("TEST2", "TEST5")(&set);
set = closure("TEST3", "TEST4")(&set);
println!("result: {:?}", set);
}
fn extract_fn<'a>(
lower: &'a str,
upper: &'a str,
) -> impl Fn(&BTreeSet<&'a str>) -> BTreeSet<&'a str> {
move |s| {
let mut r = BTreeSet::new();
r.extend(s.range(lower..=upper));
r
}
}
Except putting static lifetime, should a closure with this type of error be transformed to a function ?
This cannot be done easily but you can define your outer closure with a return type which helps you to set explicit lifetime boundaries for your inner closure. (By using for<> which is a Higher Ranked Trait Bound, you can find more details in here).
Inner closure needed to be Boxed because the size of Fn trait is not known at compile time.
let closure = |lower, upper| -> Box<for<'a> Fn(&BTreeSet<&'a str>) -> BTreeSet<&'a str>> {
Box::new(move |s: &BTreeSet<&str>| {
let mut r = BTreeSet::new();
r.extend(s.range(lower..=upper));
r
})
};
Playground

Mutable ref becomes immutable inside closure

I have this function to generate a random vector.
pub fn random_vec(r: &mut rng::Rng, n: u32) -> Vec<Flo> {
(0..n).map(|_| r.next_normal()).collect()
}
I use it to generate a vector of 3 random vectors like this.
let xs: Vec<Vec<Flo>> =
(0..3).map(|_| random_vec(&mut r, n)).collect();
This works fine. Now I try to extract this line into a function.
fn random_vecs(r: &mut rng::Rng, n: u32) -> Vec<Vec<Flo>> {
(0..3).map(|_| random_vec(&mut r, n)).collect()
}
This fails with message: "closure cannot assign to immutable argument `r`". Why does Rust want r to be immutable?
Technically, because the formal argument r of random_vecs is not mutable, and by the &mut r in the body you are trying to construct a mutable reference to it.
Here is a simplified example with the essentials of what you are doing:
fn modify0(r: &mut usize) {
*r += 1;
}
fn modify1(r: &mut usize) {
modify0(&mut r);
}
fn main() {
let mut a = 1;
modify1(&mut a);
println!("Hello, {:?}!", a);
}
The error message is
error[E0596]: cannot borrow immutable argument `r` as mutable
--> src/main.rs:6:18
|
6 | modify0(&mut r);
| ^ cannot borrow mutably
help: consider removing the `&mut`, as it is an immutable binding to a mutable reference
To fix it, you could make it mutable (don't, it's not a good idea, even though it works here):
fn modify1(mut r: &mut usize) {
modify0(&mut r);
}
Better is to follow the suggestion in the error message and remove the superfluous &mut:
fn modify1(r: &mut usize) {
modify0(r);
}

Resources