#083 Apr 15, 2026

83. Arc::unwrap_or_clone — Take Ownership Without the Dance

You need to own a T but all you have is an Arc<T>. The old pattern is a six-line fumble with try_unwrap. Arc::unwrap_or_clone collapses it into one call — and skips the clone entirely when it can.

The old dance

Arc::try_unwrap hands you the inner value — but only if you’re the last reference. Otherwise it gives your Arc back, and you have to clone.

1
2
3
4
5
6
7
8
use std::sync::Arc;

let arc = Arc::new(String::from("hello"));
let owned: String = match Arc::try_unwrap(arc) {
    Ok(inner) => inner,
    Err(still_shared) => (*still_shared).clone(),
};
assert_eq!(owned, "hello");

Every place that wanted an owned T from an Arc<T> wrote this same pattern, often subtly wrong.

The fix: unwrap_or_clone

Stabilized in Rust 1.76, Arc::unwrap_or_clone does exactly the right thing: move the inner value out if we’re the last owner, clone it otherwise.

1
2
3
4
5
use std::sync::Arc;

let arc = Arc::new(String::from("hello"));
let owned: String = Arc::unwrap_or_clone(arc);
assert_eq!(owned, "hello");

One call. No match. No deref gymnastics.

It actually skips the clone

The key win isn’t just ergonomics — it’s performance. When the refcount is 1, no clone happens; the T is moved out of the allocation directly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
use std::sync::Arc;

let solo = Arc::new(vec![1, 2, 3, 4, 5]);
let v: Vec<i32> = Arc::unwrap_or_clone(solo); // no allocation, just a move
assert_eq!(v, [1, 2, 3, 4, 5]);

let shared = Arc::new(vec![1, 2, 3]);
let _other = Arc::clone(&shared);
let v2: Vec<i32> = Arc::unwrap_or_clone(shared); // clones, because _other still holds a ref
assert_eq!(v2, [1, 2, 3]);

Also on Rc

The same method exists on Rc for single-threaded code — identical semantics, identical ergonomics:

1
2
3
4
5
use std::rc::Rc;

let rc = Rc::new(42);
let n: i32 = Rc::unwrap_or_clone(rc);
assert_eq!(n, 42);

Anywhere you were reaching for try_unwrap().unwrap_or_else(|a| (*a).clone()), reach for unwrap_or_clone instead. Shorter, clearer, and it avoids the clone when it can.

← Previous 82. isqrt — Integer Square Root Without Floating Point Next → 84. Result::flatten — Unwrap Nested Results in One Call