Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an operation for Rc or Arc which clones the underlying value and returns it to the caller?

I'm looking for something roughly like this take, but atomic:

impl<T: Clone> for Arc<T> {
    fn take(mut self) -> T {
        Arc::make_mut(&mut self);
        Arc::try_unwrap(self).unwrap()
    }
}

In other words, I want Arc::make_mut which returns the value itself, rather than a mutable reference.

like image 842
Araz Abishov Avatar asked Apr 18 '19 16:04

Araz Abishov


People also ask

What does ARC do in Rust?

'Arc' stands for 'Atomically Reference Counted'. The type Arc<T> provides shared ownership of a value of type T , allocated in the heap. Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc , while increasing a reference count.

What does RC mean in Rust?

To enable multiple ownership, Rust has a type called Rc<T> . Its name is an abbreviation for reference counting, which keeps track of the number of references to a value to know whether or not a value is still in use.

What does clone do in Rust?

Returns a copy of the value.

Is RC send Rust?

Rc uses non-atomic reference counting. This means that overhead is very low, but an Rc cannot be sent between threads, and consequently Rc does not implement Send . As a result, the Rust compiler will check at compile time that you are not sending Rc s between threads.


1 Answers

We can use the * deref operator to address the underlying value inside of an Rc or Arc, and then call .clone() to return a new owned clone of that value (assuming it's clonable).

use std::rc::Rc;

fn main() { 
    let rc = Rc::new("Hello".to_string());
    let mut cloned = (*rc).clone();
    cloned.truncate(4);

    // verify that it's modified
    println!("{:?}", cloned); // "Hell"
    // verify that the original was not
    println!("{:?}", rc); // "Hello"
}

The Rc/Arc semantics will prevent any mutable references from being created while your reference exists, so this operation is thread-safe; the data can't be changed while you're cloning it. You also don't need a mutable reference to the original underlying value, because you're not modifying it.

In some cases, Rust lets you omit the * deref operator: it will implicitly dereference a non-mutable pointer type if you try to call a method that doesn't exist on the pointer, but does exist on the underlying value. However, we need to be explicit in this case because a .clone() method does already exists on Rc/Arc: it's used to create a new reference to the same value. We don't want to call that, so we need to explicitly dereference to access the inner type's .clone() instead.

We can also tell Rust which .clone() method we want by explicitly calling it through the appropriate type, and the compiler will implicitly apply as many dereferences as necessary.

use std::rc::Rc;

fn main() { 
    let rc3 = Rc::new(Rc::new(Rc::new("Hello".to_string())));
    let mut cloned = String::clone(&rc3);
    cloned.truncate(4);

    // verify that it's modified
    println!("{:?}", cloned); // "Hell"
    // verify that the original was not
    println!("{:?}", rc3); // "Hello"
}
like image 122
Jeremy Avatar answered Sep 28 '22 03:09

Jeremy