Skip to content

Instantly share code, notes, and snippets.

@max-itzpapalotl
Last active February 25, 2024 14:44
Show Gist options
  • Save max-itzpapalotl/59d634e0cc83287a8992ad76213fae05 to your computer and use it in GitHub Desktop.
Save max-itzpapalotl/59d634e0cc83287a8992ad76213fae05 to your computer and use it in GitHub Desktop.
23. The marker traits Copy, Clone, Send and Sync

23. The marker traits Copy, Clone, Send and Sync

Copy

#[derive(Debug)]
struct Point {
    pub x: u32,
    pub y: u32,
}

fn main() {
    let a = Point{x: 10, y: 12};
    let b = a;    // Move semantics
    // println!("Name: {}, Age: {}", a.x, a.y);    // can not use here
    println!("Name: {}, Age: {}", b.x, b.y);
}

With Copy and Clone the value can be copied:

#[derive(Debug, Copy, Clone)]
struct Point {
    pub x: u32,
    pub y: u32,
}

fn main() {
    let a = Point{x: 10, y: 12};
    let b = a;    // Copy semantics
    println!("Name: {}, Age: {}", a.x, a.y);    // allowed
    println!("Name: {}, Age: {}", b.x, b.y);
}

Clone has two methods clone and clone_from:

#[derive(Debug, Copy, Clone)]
struct Point {
    pub x: u32,
    pub y: u32,
}

fn main() {
    let a = Point{x: 10, y: 12};
    let mut b = Point{x: 0, y: 0};
    b.clone_from(&a);
    println!("Name: {}, Age: {}", a.x, a.y);
    println!("Name: {}, Age: {}", b.x, b.y);
}

Most scalar types are Copy, immutable references are, too, but String is not:

fn test_copy<T: Copy>(_t:T) {}

fn main() {
    let x: i64 = 12;
    let y: String = "abc".to_string();
    test_copy(x);
    test_copy(y);   // Compile error, since String is not Copy
}

Send and Sync

These are often perceived to be difficult. You have to know 3 things:

  1. A type T is Send, if it is safe to send objects of type T between threads.
  2. A type T is Sync, if it is safe to share objects of type T between threads and use them concurrently.
  3. A type T is Sync, if and only if &T is Send.

Contrary to other traits, Send and Sync are usually derived automatically by the compiler from what it already knows. Most elementary types are both Send and Sync, but most (smart) pointers are not. A struct is Send (or Sync resp.), if and only if all its components are Send (or Sync respectively.

We investigate our smart pointers:

#[derive(Debug)]
struct Person {
    pub name: String,
    pub age: u32,
}

fn test_copy<T: Copy>(_t: T) { }
fn test_clone<T: Clone>(_t: T) { }
fn test_send<T: Send>(_t: T) { }
fn test_sync<T: Sync>(_t: T) { }

fn main() {
    {
        let mut b = Box::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);  // error: not clone
        test_send(b);
        test_sync(b);
    }

    {
        let mut b = std::rc::Rc::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);
        test_send(b);   // error: not send
        test_sync(b);   // error: not sync
    }

    {
        let mut b = std::sync::Arc::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);
        test_send(b);
        test_sync(b);
    }

    {
        let b = std::sync::Mutex::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);  // error: not clone
        test_send(b);
        test_sync(b);

        let bb = b.lock().unwrap();
        test_copy(bb);   // error: not copy
        test_clone(bb);  // error: not clone
        test_send(bb);   // error: not send
        test_sync(bb);
    }

    {
        let b = std::sync::RwLock::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);  // error: not clone
        test_send(b);
        test_sync(b);

        {
            let bb = b.write().unwrap();
            test_copy(bb);   // error: not copy
            test_clone(bb);  // error: not clone
            test_send(bb);   // error: not send
            test_sync(bb);
        }

        let bbb = b.read().unwrap();
        test_copy(bbb);   // error: not copy
        test_clone(bbb);  // error: not clone
        test_send(bbb);   // error: not send
        test_sync(bbb);
    }

    {
        let b = std::cell::RefCell::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);  // error: not clone
        test_send(b);
        test_sync(b);   // error: not sync
    }

    {
        let b = std::cell::Cell::new(Person{name: "Max".into(), age: 54});
        test_copy(b);   // error: not copy
        test_clone(b);  // error: not clone
        test_send(b);
        test_sync(b);   // error: not sync
    }
}

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment