[Solved] Channel in a loop in a thread: borrowed value does not live long enough

Hmm, your example was more difficult than the standard one since you had to use two levels of closures.

Since both are given to other threads, there are lifetime issues involved (see this post of mine explaining why), so you need a runtime mechanism to guarantee that the referee only gets dropped when there are no (owning) references left, which is what Arc does.

Whenever some x: T is "mentioned" in a closure that uses it by shared reference (e.g., printing it, or in your example, .lock()ing it), the closure will use by default &x: &T whenever you "mention" it, which requires that the closure do not outlive the local frame of x (Rust will raise an error when that can happen, such as with threads).

The solution, to avoid feeding &x: &T to the closure, is to feed it "a magic reference that artificially keeps the (heap-allocated) referee alive" a Arc<T>.

For that to happen, you need to use a move closure to force take ownership of the captures (i.e., prevent having &_ in the captures). Note that up until this point the key is about using a move closure, Arc is not needed yet.

Where Arc<T> shines is to solve the issue you had: after giving a variable to a move closure, you cannot use it again (unless it is Copy).

The solution, which Arc was designed for, is to (cheaply) .clone() it so that what the closure captures is a "clone" of your local.

  • The cloning is guaranteed to be "cheap" since all that Arc-cloning does is incrementing a counter, which is the way to "artifically keep the (heap-allocated) referee alive".

Back to your example and the two levels of closures, since you did not use server_sender_arc outside the first move closure, you did not need to .clone() it. But then, within that outer closure, you did need to use it multiple times (c.f. the loop). Hence the cloning.

It shadows the local var for ergonomics, but only withing the scope of the loop, so all is fine: it may have been more beginner friendly if the clone had been declared with a different name, and if I had used that name in the inner closure.

You could mark my previous answer as the solving one (symbol below any post).