Dereferencing an Arc<T>

Hi,
I have a variable inside a function of type Arc , however I want to return only the parameter inside Arc. Any idea on how to dereference it?

like this: *the_arc

The type T does not have copy trait, so when I try to dereference it using *, it throws an error

Well, if you are trying to move something from behind indirection, that's not going to be possible. In safe code, references and other pointer-like types always have to point to a valid value. Maybe what you are really trying to do is just return a reference to the contents of the Arc? It would be helpful if you showed some actual code and elaborated on your actual, high-level requirements – this seems like an XY problem.

The reason for that is because the Arc is Atomically Reference Counted, and the pointer could be owned by many threads at the same time, making it unsafe to move the value out of the Arc.

[Edit: Rc is wrong, you can't move out of shared pointers, as pointed out later in thread;An Rc or a] Box on the other hand can have its value moved out.

If you "Must" use an Arc, and you "Must" move out of it, then you also Must protect the value accordingly, for example as Arc<Mutex<Option<T>>> — you take the lock, and then .take() the Some out of the Option and leave a None in its place.

The short answer to all the above is — a single value can only have a single owner.

Does that make sense?

No, not an Rc. The issue is not multiple threads, it's multiple owners. (Accordingly, both types feature a try_unwrap() method that gives away ownership if the pointer is unique, but that's hardly ever what one actually needs.)

use std::sync::Arc;

struct S(pub String);

fn main() {
    let arc = Arc::new(S("Hello World!".to_string()));
    let ref1 = &*arc; // `ref1` has type `&S`
    println!("{}", ref1.0);
    let ref2: &S = &arc;
    println!("{}", ref2.0);
    //let _arc_clone = arc.clone(); // cloning the `Arc` will make `try_unwrap` fail
    let s = match Arc::try_unwrap(arc) {
        Ok(x) => x,
        Err(_) => panic!("clone existed")
    };
    println!("{}", s.0);
}

(Playground)

Output:

Hello World!
Hello World!
Hello World!

Ah, yep that's right, my bad :grimacing:

If the inner type is Clone, you can get a clone without moving T with something like (*the_arc).clone(). Rust Playground Can be useful when you want to keep the original Arc<T> around for later.

1 Like