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

1

17

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());
}
Violetavioletta answered 19/5, 2020 at 19:9 Comment(4)
if you need owner ship ask owner ship if you not, don't.Stope
@Shepmaster edited my original question a bit too aggressively I think. My struct wants ownership of a copy, not ownership of the original.Violetavioletta
there's not much of a difference, if you need an owned object you should ask for it, the caller can decide whether to clone or transfer ownershipOverstrung
@AndrewMoffat specifically, your struct cannot know that it's a copy because that's only something that the creator of the struct can decide.Rune
R
14

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:

Rune answered 19/5, 2020 at 19:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.