Rust lifetime - Book example solution - rust

On Rust Book there's this lifetime example:
struct Foo<'a> {
x: &'a i32,
}
fn main() {
let x; // -+ x goes into scope
// |
{ // |
let y = &5; // ---+ y goes into scope
let f = Foo { x: y }; // ---+ f goes into scope
x = &f.x; // | | error here
} // ---+ f and y go out of scope
// |
println!("{}", x); // |
}
Simplifying this to:
fn main() {
let x;
{
let y = 42;
x = &y;
}
println!("The value of 'x' is {}.", x);
}
Is it possible to have it work without clone?

In this example, you can simply enlarge the lifetime of y by removing the scope introduced by the curly braces.
fn main() {
let x;
let y = 42;
x = &y;
println!("The value of 'x' is {}.", x);
}
Or, as others suggested, you can transfer the ownership from y to x, i.e. move the value from y to x, by removing the reference operator & from y:
fn main() {
let x;
{
let y = 42;
x = y;
}
println!("The value of 'x' is {}.", x);
}

Related

Non-lexical lifetimes

Can someone explain the following, please?
this compiles (explanation: NLL y not referenced after initial definition?)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("z: {}", z);
}
this doesn't compile (explanation: z not referenced but only introduced the line before so still active?)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("y: {}", y);
}
this compiles (explanation: NLL z not referenced after initial definition?)
fn main() {
let mut x = 5;
let z = &mut x;
let y = &x;
println!("y: {}", y);
}
this doesn't compile (just to see whether introducing lines would lead to z not being active by the println)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
}
I'm confused... I couldn't find anything that covers this specific case in the book but if somebody has a link to something that explains this behaviour, I would appreciate it.
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
// 'y lifetime ends (never used later), releasing hold on x
let z = &mut x; // this is fine because the hold is released
println!("z: {}", z);
}
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
let z = &mut x; // this is forbidden because of the existing hold
println!("y: {}", y);
// 'y lifetime ends, releasing hold on x
}
fn main() {
let mut x = 5;
let z = &mut x;
// 'z lifetime starts, holding a mutable reference to x
// 'z lifetime ends (never used later), releasing hold on x
let y = &x; // this is fine because the hold is released
println!("y: {}", y);
// 'y lifetime ends, releasing hold on x
}
Pretty much the same as #2
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
let z = &mut x; // this is forbidden because of the existing hold
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
// 'y lifetime ends, releasing hold on x
}
As you know, no other references can exist while a mutable reference to some data also exists. You will see &mut also called "exclusive references" for this reason.
The borrow checker is what enforces this, using the lifetimes of the references in your code. In older versions of Rust, all lifetimes were "lexical" - they would last as long as their containing scope. "Non-lexical lifetimes" were introduced to make things easier for the programmer, by making it so reference lifetimes would only last as long as those references were used.
This is what allows examples #1 and #3 to work. A reference is created but the lifetime immediately ends because they aren't used later, so there is no overlap of lifetimes when the next line creates a different reference.
It's useful to look at the lifetime of every variable here. Let's look example by example.
// example one
fn main() {
let mut x = 5;
let y = &x; // y is declared here, but never used
// so its lifetime is effectively nil
let z = &mut x; // by this line, it no longer exists
println!("z: {}", z);
}
// example two
fn main() {
let mut x = 5;
let y = &x; // y is declared here and used in the
// println, so...
let z = &mut x; // ...this is invalid, since you cannot
// take a mutable reference when you have
// an existing reference.
println!("y: {}", y);
}
// example three
fn main() {
let mut x = 5;
let z = &mut x; // z is declared here but never used
// so its lifetime is effectively nil
let y = &x; // by this line, it no longer exists
println!("y: {}", y);
}
// example four
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x; // This is functionally identical to ex. 2
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
}

Why is this lifetime function possible?

I've discovered some behavior I cannot explain. I've written this function:
fn main() {
let word_one = "ONE";
let x;
{
let word_two = "THREE";
x = get_ref(&word_one, &word_two);
}
println!("{}", x);
}
fn get_ref<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.chars().count() >= b.chars().count() {
return a;
}
return b;
}
This function is possible, even if the lifetime of word_two isn't long enough to build a reference. Otherwise this example isn't possible:
fn main() {
let word_one = "ONE";
let x;
{
let word_two = "THREE";
x = &word_two;
}
println!("{}", x);
}
Unfortunately I've discovered nothing in the docs which would explain this behavior.
Rust's auto-derefencing rules are messing you up. What you've written is syntactic sugar for the following:
fn main() {
let word_one = "ONE";
let x;
{
let word_two = "THREE";
x = get_ref(word_one, word_two);
}
println!("{}", x);
}
fn get_ref<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.chars().count() >= b.chars().count() {
return a;
}
return b;
}
This is because word_one and word_two are of type & 'static str. They are references to underlying string objects which have been statically allocated.
On the other hand,
let x;
{
let word = "word";
x = &word;
}
does not work because there is no dereferencing magic. &word is of type &'a &'static str where 'a is the lifetime bounded by the braces. So the value does not live long enough.

Problems with lifetime/borrow on str type

Why does this code compile?
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let x = "eee";
let &m;
{
let y = "tttt";
m = longest(&x, &y);
}
println!("ahahah: {}", m);
}
For me, there should be a compilation error because of lifetimes.
If I write the same code with i64, I get an error.
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
let x = 3;
let &m;
{
let y = 5;
m = ooo(&x, &y);
}
println!("ahahah: {}", m);
}
The error is:
error[E0597]: `y` does not live long enough
--> src/main.rs:103:25
|
103 | m = ooo(&x, &y);
| ^^ borrowed value does not live long enough
104 | }
| - `y` dropped here while still borrowed
105 | println!("ahahah: {}", m);
| - borrow later used here
There are a few things we need to know to understand this. The first is what the type of a string literal is. Any string literal (like "foo") has the type &'static str. This is a reference to a string slice, but moreover, it's a static reference. This kind of reference lasts for the entire length of the program and can be coerced to any other lifetime as needed.
This means that in your first piece of code, x and y are already both references and have type &'static str. The reason the call longest(&x, &y) still works (even though &x and &y have type &&'static str) is due to Deref coercion. longest(&x, &y) is really de-sugared as longest(&*x, &*y) to make the types match.
Let's analyze the lifetimes in the first piece of code.
fn main() {
// x: &'static str
let x = "eee";
// Using let patterns in a forward declaration doesn't really make sense
// It's used for things like
// let (x, y) = fn_that_returns_tuple();
// or
// let &x = fn_that_returns_reference();
// Here, it's the same as just `let m;`.
let &m;
{
// y: &'static str
let y = "tttt";
// This is the same as `longest(x, y)` due to autoderef
// m: &'static str
m = longest(&x, &y);
}
// `m: &static str`, so it's still valid here
println!("ahahah: {}", m);
}
(playground)
With the let &m; you may have meant something like let m: &str to force its type. This I think actually would ensure that the lifetime of the reference in m starts with that forward declaration. But since m has type &'static str anyway, it doesn't matter.
Now let's look at the second version with i64.
fn main() {
// x: i64
// This is a local variable
// and will be dropped at the end of `main`.
let x = 3;
// Again, this doesn't really make sense.
let &m;
// If we change it to `let m: &i64`, the error changes,
// which I'll discuss below.
{
// Call the lifetime roughly corresponding to this block `'block`.
// y: i64
// This is a local variable,
// and will be dropped at the end of the block.
let y = 5;
// Since `y` is local, the lifetime of the reference here
// can't be longer than this block.
// &y: &'block i64
// m: &'block i64
m = ooo(&x, &y);
} // Now the lifetime `'block` is over.
// So `m` has a lifetime that's over
// so we get an error here.
println!("ahahah: {}", m);
}
(playground)
If we change the declaration of m to let m: &i64 (which is what I think you meant), the error changes.
error[E0597]: `y` does not live long enough
--> src/main.rs:26:21
|
26 | m = ooo(&x, &y);
| ^^ borrowed value does not live long enough
27 | } // Now the lifetime `'block` is over.
| - `y` dropped here while still borrowed
...
30 | println!("ahahah: {}", m);
| - borrow later used here
(playground)
So now we explicitly want m to last as long as the outer block, but we can't make y last that long, so the error happens at the call to ooo.
Since both these programs are dealing with literals, we actually can make the second version compile. To do this, we have to take advantage of static promotion. A good summary of what that means can be found at the Rust 1.21 announcement (which was the release the introduced this) or at this question.
In short, if we directly take a reference to a literal value, that reference may be promoted to a static reference. That is, it's no longer referencing a local variable.
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
// due to promotion
// x: &'static i64
let x = &3;
let m;
{
// due to promotion
// y: &'static i64
let y = &5;
// m: &'static i64
m = ooo(x, y);
}
// So `m`'s lifetime is still active
println!("ahahah: {}", m);
}
(playground)
Your examples are not exactly the same. A string literal, "eee" has type &str, not str, so the corresponding code with integers looks like this:
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
let x = &3;
let &m;
{
let y = &5;
m = ooo(&x, &y);
}
println!("ahahah: {}", m);
}
And it compiles.
The reason that this (and the &str example) works is because local inline literal references are given the 'static lifetime. That is, they are placed in the static data portion of the final binary and are available in memory for the full lifespan of the program.

Value moved here, in previous iteration of loop

This is what I wrote for LeetCode: Add Two Numbers
//2. Add Two Numbers
// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>,
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode { next: None, val }
}
}
struct Solution;
impl Solution {
pub fn list_to_num(ls: &Option<Box<ListNode>>) -> i64 {
let mut vec = vec![];
let mut head = ls;
while let Some(node) = head {
vec.push(node.val);
head = &node.next;
}
vec.reverse();
let mut num = 0i64;
for x in vec {
num *= 10;
num += x as i64;
}
num
}
pub fn num_to_list(num: i64) -> Option<Box<ListNode>> {
let num_str = num.to_string();
let vec = num_str
.chars()
.map(|x| x.to_digit(10).unwrap() as i32)
.collect::<Vec<_>>();
let mut res = None;
for x in vec {
let mut one = ListNode::new(x);
one.next = res;
res = Some(Box::new(one));
}
res
}
pub fn add_two_numbers(
l1: Option<Box<ListNode>>,
l2: Option<Box<ListNode>>,
) -> Option<Box<ListNode>> {
let mut vec = vec![] as Vec<i32>;
let mut step = 0;
let mut left = l1;
let mut right = l2;
loop {
match (left, right) {
(None, None) => {
if step != 0 {
vec.push(step);
}
break;
}
(Some(leftN), None) => {
let curr = leftN.val + step;
if curr >= 10 {
vec.push(curr - 10);
step = 1
} else {
vec.push(curr);
step = 0
}
left = leftN.next
}
(None, Some(rightN)) => {
let curr = rightN.val + step;
if curr >= 10 {
vec.push(curr - 10);
step = 1
} else {
vec.push(curr);
step = 0
}
right = rightN.next
}
(Some(leftN), Some(rightN)) => {
let curr = leftN.val + rightN.val + step;
if curr >= 10 {
vec.push(curr - 10);
step = 1
} else {
vec.push(curr);
step = 0
}
right = rightN.next;
left = leftN.next
}
}
}
vec.reverse();
let mut res = None;
for x in vec {
let mut next = ListNode::new(x);
next.next = res;
res = Some(Box::new(next));
}
res
}
}
fn main() {
let list1 = Solution::num_to_list(9);
let list2 = Solution::num_to_list(991);
println!("list1 {:?}", list1);
println!("list2 {:?}", list2);
let res = Solution::add_two_numbers(list1, list2);
println!("summed {:#?}", res);
}
I get a compile error
error[E0382]: use of moved value: `left`
--> src/main.rs:66:20
|
63 | let mut left = l1;
| -------- move occurs because `left` has type `std::option::Option<std::boxed::Box<ListNode>>`, which does not implement the `Copy` trait
...
66 | match (left, right) {
| ^^^^ value moved here, in previous iteration of loop
error[E0382]: use of moved value: `right`
--> src/main.rs:66:26
|
64 | let mut right = l2;
| --------- move occurs because `right` has type `std::option::Option<std::boxed::Box<ListNode>>`, which does not implement the `Copy` trait
65 | loop {
66 | match (left, right) {
| ^^^^^ value moved here, in previous iteration of loop
I think each iteration is independent, and if the value is borrowed by a previous iteration, it should be returned in "this" iteration.
If I replace match (left, right) { with match (left.clone(), right.clone()) {, the code compiles, but it might consume more memory than necessary. What is the better way to make it compile and be memory economical?
You're not borrowing the nodes, you're moving them.
In order to use references, you should replace
let mut left = l1;
let mut right = l2;
with
let mut left = &l1;
let mut right = &l2;
and then later
right = rightN.next;
with
right = &rightN.next;
etc.
playground

How to pass multiple args to a rust closure - expected closure that takes 1 argument

I am new to closures and I don't understand why I am getting the following error.
If I don't include the second argument its works:
fn obj_x(x: Vec<f64>) -> f64 {
return 0.0;
};
let f = |x: &Vec<f64>| obj_x(x.to_vec());
Here is my closure:
fn foo() {
let f = |x: &Vec<f64>, N: usize| obj_x(x.to_vec(), N);
}
fn obj_x(x: Vec<f64>, N: usize) -> f64 {
let x = (x[0] + 4.0).powf(2.0);
return x;
}
But unfortunately it fails
error[E0593]: closure is expected to take 1 argument, but it takes 2 arguments
--> src/main.rs:120:44
|
114 | let f = |x: &Vec<f64>, N: usize | obj_x(x.to_vec(),N);
| ------------------------- takes 2 arguments
...
120 | let mut fmin = Funcmin::new(&mut x,&f,&g,"cg");
| ^^ expected closure that takes 1 argument
|
Here is my full code:
fn obj_x(x: Vec<f64>, N: usize) -> f64 {
let x = (x[0] + 4.0).powf(2.0);
return x;
}
fn gradient_x(x: Vec<f64>) -> Vec<f64> {
return vec![2.0 * (x[0] + 4.0)];
}
fn test() {
let f = |x: &Vec<f64>, &N: usize| obj_x(x.to_vec(), N);
let g = |x: &Vec<f64>| gradient_x(x.to_vec());
let mut x = vec![40.0f64];
let mut N = 2220;
{
//you must create a mutable object
let mut fmin = Funcmin::new(&mut x, &f, &g, "cg");
fmin.minimize();
}
println!("{:?}", x);
}
This solution worked for me: declare
fn fold(n: u32, init: u32, op: impl Fn(u32, u32) -> u32) -> u32 {...
and call it as
fold(n, 1, |x: u32, y: u32| -> u32 {x + y })

Resources