HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustMajor

How does Rust provide move semantics?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
howmovesemanticsdoesrustprovide

Problem

The Rust language website claims move semantics as one of the features of the language. But I can't see how move semantics are implemented in Rust.

Rust boxes are the only place where move semantics are used.
let x = Box::new(5);
let y: Box = x; // x is 'moved'


The above Rust code can be written in C++ as
auto x = std::make_unique(5);
auto y = std::move(x); // Note the explicit move


As far as I know (correct me if I'm wrong),

  • Rust doesn't have constructors at all, let alone move constructors.



  • No support for rvalue references.



  • No way to create functions overloads with rvalue parameters.



How does Rust provide move semantics?

Solution

I think it's a very common issue when coming from C++. In C++ you are doing everything explicitly when it comes to copying and moving. The language was designed around copying and references. With C++11 the ability to "move" stuff was glued onto that system. Rust on the other hand took a fresh start.


Rust doesn't have constructors at all, let alone move constructors.

You do not need move constructors. Rust moves everything that "does not have a copy constructor", a.k.a. "does not implement the Copy trait".

struct A;

fn test() {
    let a = A;
    let b = a;
    let c = a; // error, a is moved
}


Rust's default constructor is (by convention) simply an associated function called new:

struct A(i32);
impl A {
    fn new() -> A {
        A(5)
    }
}


More complex constructors should have more expressive names. This is the named constructor idiom in C++


No support for rvalue references.

It has always been a requested feature, see RFC issue 998, but most likely you are asking for a different feature: moving stuff to functions:

struct A;

fn move_to(a: A) {
    // a is moved into here, you own it now.
}

fn test() {
    let a = A;
    move_to(a);
    let c = a; // error, a is moved
}



No way to create functions overloads with rvalue parameters.

You can do that with traits.

trait Ref {
    fn test(&self);
}

trait Move {
    fn test(self);
}

struct A;
impl Ref for A {
    fn test(&self) {
        println!("by ref");
    }
}
impl Move for A {
    fn test(self) {
        println!("by value");
    }
}
fn main() {
    let a = A;
    (&a).test(); // prints "by ref"
    a.test(); // prints "by value"
}

Code Snippets

struct A;

fn test() {
    let a = A;
    let b = a;
    let c = a; // error, a is moved
}
struct A(i32);
impl A {
    fn new() -> A {
        A(5)
    }
}
struct A;

fn move_to(a: A) {
    // a is moved into here, you own it now.
}

fn test() {
    let a = A;
    move_to(a);
    let c = a; // error, a is moved
}
trait Ref {
    fn test(&self);
}

trait Move {
    fn test(self);
}

struct A;
impl Ref for A {
    fn test(&self) {
        println!("by ref");
    }
}
impl Move for A {
    fn test(self) {
        println!("by value");
    }
}
fn main() {
    let a = A;
    (&a).test(); // prints "by ref"
    a.test(); // prints "by value"
}

Context

Stack Overflow Q#29490670, score: 72

Revisions (0)

No revisions yet.