Lifetime issue in implementing a simple list

I'm following Final Code - Learning Rust With Entirely Too Many Linked Lists (rust-unofficial.github.io) to build an immutable linked list.

use std::rc::Rc;

pub struct SList<T> {
	head : SLink<T>,
}

pub struct Iter<'a, T> {
	next : Option<&'a SNode<T>>
}

type SLink<T> = Option<Rc<SNode<T>>>;

struct SNode<T> {
	next : SLink<T>,
	elem : T,
}

impl<T> SList<T> {
	pub fn new() -> Self {
		SList { head : None }
	}

	pub fn append(&self, elem: T) -> SList<T> {
		SList { head:
			Some(Rc::new(SNode{
				next: self.head.clone(),
				elem: elem,
		}))}
	}

	pub fn head(&self) -> Option<&T> {
		self.head.as_ref().map(|node| &node.elem)
	}

	pub fn tail(&self) -> SList<T> {
		SList { head: self.head.as_ref().and_then(|node| node.next.clone()) }
	}

	pub fn iter(&self) -> Iter<'_, T> {
		Iter { next: self.head.as_deref() }
	}
}

impl<'a, T> Iterator for Iter<'a, T> {
	type Item = &'a T;
	fn next(&mut self) -> Option<Self::Item> {
		self.next.map(|node| {
			self.next = node.next.as_deref();
			&node.elem
		})
	}
}

#[cfg(test)]
mod tests {
	use super::SList;

	#[test]
	fn tail() {
		let l0 = SList::<i32>::new();
		let l1 = l0.append(1);
		let l2 = l1.append(2);
		let adder = |accu, item| { accu + item };

		assert_eq!(l0.tail().iter().fold(0i32, adder), 0);
		assert_eq!(l1.tail().iter().fold(0i32, adder), 0);
		assert_eq!(l2.tail().iter().fold(0i32, adder), 1);
	}
}

After ran cargo test on this code, I got this error

error[E0716]: temporary value dropped while borrowed
  --> src\immutable\slist.rs:65:14
   |
65 |         assert_eq!(l0.tail().iter().fold(0i32, adder), 0);
   |         -----------^^^^^^^^^------------------------------
   |         |          |
   |         |          creates a temporary which is freed while still in use
   |         temporary value is freed at the end of this statement
66 |         assert_eq!(l1.tail().iter().fold(0i32, adder), 0);
   |                                                ----- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

error[E0716]: temporary value dropped while borrowed
  --> src\immutable\slist.rs:66:14
   |
66 |         assert_eq!(l1.tail().iter().fold(0i32, adder), 0);
   |         -----------^^^^^^^^^------------------------------
   |         |          |
   |         |          creates a temporary which is freed while still in use
   |         temporary value is freed at the end of this statement
67 |         assert_eq!(l2.tail().iter().fold(0i32, adder), 1);
   |                                                ----- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

Why there is a borrow here ? I thought l1.tail() and l2.tail() are completely independent.

adder's type is inferred to be something that implements Fn(i32, &'a i32), but the problem is that 'a lifetime, what should it be? My guess is that the compiler gives it the lifetime of the items of l0/l1, however what you want is that the closure should be generic over that lifetime. Here are some way to fix this:

  • Explicit that adder has type for<'a> fn(i32, &'a i32) -> i32, thus fixing the type inference.
  • Explicit that item (the parameter of adder) has type &i32, thus (somehow, idk why in this case) fixing the type inference.
  • Add .copied() before the fold, thus preventing from passing any reference to the closure, and with that any inference shenanigan.

Ah! So the borrow is on adder, I thought the compiler was talking about the temporary l0.tail(). Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.