Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it more conventional to pass-by-value or pass-by-reference when the method needs ownership of the value?

When I'm passing a object by reference to a struct's new() method, and the struct will own the object, is it more conventional to:

  • pass the object by reference, and do to_owned() in the new()
  • clone the object before calling new(), and pass by value, moving it

I can think of pros and cons of each in terms of clarity and separation-of-concerns.

#[derive(Clone)]
struct MyState;

struct MyStruct {
    state: MyState,
}

impl MyStruct {
    pub fn new_by_ref(state: &MyState) -> Self {
        MyStruct {
            state: state.to_owned(),
        }
    }

    pub fn new_by_val(state: MyState) -> Self {
        MyStruct { state }
    }
}

fn main() {
    let state1 = MyState;
    let struct1 = MyStruct::new_by_ref(&state1);

    let state2 = MyState;
    let struct2 = MyStruct::new_by_val(state2.clone());
}
like image 708
Andrew Moffat Avatar asked May 19 '20 19:05

Andrew Moffat


People also ask

Is pass by value more efficient than pass by reference?

Pass-by-references is more efficient than pass-by-value, because it does not copy the arguments. The formal parameter is an alias for the argument. When the called function read or write the formal parameter, it is actually read or write the argument itself.

Why is it usually better to pass objects by reference than by value?

The reason is simple: if you passed by value, a copy of the object had to be made and, except for very small objects, this is always more expensive than passing a reference.

Is it better to pass by reference?

2) For passing large sized arguments: If an argument is large, passing by reference (or pointer) is more efficient because only an address is really passed, not the entire object.

What's the difference between pass by reference and pass by value?

Basically, pass-by-value means that the actual value of the variable is passed and pass-by-reference means the memory location is passed where the value of the variable is stored.


1 Answers

Pass by value.

This way, the program can avoid unnecessarily doubly-allocating the value if the caller no longer needs it.


In many cases, I recommend accepting anything that can be made into the owned type. This is easily demonstrated with String:

struct MyStruct {
    state: String,
}

impl MyStruct {
    fn new(state: impl Into<String>) -> Self {
        let state = state.into();
        MyStruct { state }
    }
}

fn main() {
    let struct1 = MyStruct::new("foo");
    let struct2 = MyStruct::new(String::from("bar"));
}

See also:

  • How to accept str, String and &String in a single rust function
like image 155
Shepmaster Avatar answered Nov 24 '22 14:11

Shepmaster