(edited conversation from #rust, featuring jml, reem, and Yurume).
I have a value type Foo, implemented as a struct with methods that return Foo such that the struct is never mutated but only new ones returned. If I want one of those to return the value unchanged, do I have to clone? e.g. http://is.gd/rm4gmY
#[deriving(Eq, PartialEq, PartialOrd, Ord, Show, Clone)]
struct Foo {
x: int,
}
impl Foo {
fn new(x: int) -> Foo {
Foo { x: x }
}
/// Returns a new version of self if the flag is set, otherwise returns
/// the old one.
fn some_operation(&self, p: bool) -> Foo {
if p {
Foo { x: 2 * self.x }
} else {
// XXX: Do I have to clone here? Is there some way to just return self?
self.clone()
}
}
}
fn main() {
let foo = Foo::new(5);
println!("foo: {}", foo);
let bar = foo.some_operation(true);
let baz = foo.some_operation(false);
println!("bar: {}", bar);
println!("baz: {}", baz);
}Because some_operation is taking a reference to &self, it needs to clone.
(XXX - understand and explain why. I'm pretty sure I can figure this out for
myself - jml)
The method can be changed to take self as a value, but then you won't be
able to re-use one instance of Foo.
In this case you'll actually have no problem, since Foo is all
Copy data, but if Foo is
owned (meaning it contains data that has a destructor, has a destructor, or is
not Copy) then calling a self method transfers ownership into the method,
meaning you can no longer use it.
This example demonstrates the re-use problem:
#[deriving(Eq, PartialEq, PartialOrd, Ord, Show, Clone)]
struct Foo {
xs: Vec<int>,
}
impl Foo {
fn new(x: int) -> Foo {
Foo { xs: vec![x] }
}
/// Returns a new version of self if the flag is set, otherwise returns
/// the old one.
fn some_operation(self, y: Option<int>) -> Foo {
match y {
Some(x) => {
let mut ys = self.xs.clone();
ys.push(x);
Foo { xs: ys }
},
None => self,
}
}
}
fn main() {
let foo = Foo::new(5);
println!("foo: {}", foo);
let bar = foo.some_operation(Some(4));
let baz = foo.some_operation(None);
println!("bar: {}", bar);
println!("baz: {}", baz);
}The first use moves it so the second use can't use it.
Changing Foo to store an Rc<Vec<T>> might make it possible to avoid the
clone(). Rc only gives
immutable access though. Really, this use case requires a persistent data
structure.
Rust doesn't have one, but there are third-party libraries available, such as https://github.com/michaelwoerister/rs-persistent-datastructures.
For this particular use-case, it might be reasonable to roll my own linked list.
See also the Rust guide and the ownership guide.
If you do implement some persistent data structures, make an issue or PR in https://github.com/gankro/collect-rs.