I'm a Rust newbie trying to figure out the language by playing with it. I've hit some problems on trying to return an array from a function:
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings(&self) -> ~[int] {
self.thingies
}
}
fn main() {
let widget = Widget::new();
let wotsits = widget.somethings();
}
This of course fails compilation with this error:
pointers.rs:11:8: 11:21 error: cannot move out of dereference of & pointer
pointers.rs:11 self.thingies
In case this code sample looks out of sorts, all I'm trying to do is pull an array out of an implemented struct. The borrowed pointer isn't important, it's just how I'm trying to store the data.
Any tips on how to extract my array properly?
Btw, I'm using Rust 0.8
The reason your code doesn't compile is that a unique pointer ~
can have only one owner. The compiler is preventing you from writing error prone code. You can either decide to return a copy of thingies, a reference to thingies, or a slice of thingies (which is a reference to the vector data or a segment of it).
Copy solution
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings(&self) -> ~[int] {
self.thingies.clone()
}
}
Reference solution
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings<'a>(&'a self) -> &'a~[int] {
&self.thingies
}
}
Slice solution
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings<'a>(&'a self) -> &'a[int] {
self.thingies.as_slice()
}
}
To understand the reference and slice solutions you need to understand what 'a
means: it indicates a lifetime, and &'a
is a way to tell the compiler that the reference must never outlive the object it references, which in this case is a Widget.
These solutions also have some limitations: you cannot modify an object that you're currently referencing because doing so opens up the possibility of the references becoming invalid.
You can of course modify thingies if you return a mutable reference. A mutable reference with a lifetime would be written &'a mut T
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings<'a>(&'a mut self) -> &'a mut ~[int] {
&mut self.thingies
}
}
Note I believe that in Rust 0.8, you need to write &'self
instead of &'a
because lifetimes with custom names weren't supported yet. I also wrote this in 0.9.
Edit: removed redundant lifetime declarations.
=== EDIT ===
in Rust 1 stable, ~[T]
became Vec<T>
, but (syntax aside) the same issue applies, as a Vec still has a unique owner. In a nutshell, somethings
only has a reference to self and (through the reference) it can't become the owner of thingies
. Playground link to Rust 1 version here: https://play.rust-lang.org/?gist=50ec1acdc684e53fd5f9&version=stable.
Rust's ownership model is quite central to the language, so for more info I'd suggest looking at the great official documentation on ownership and borrowing
=== END EDIT ===
In Rust, the .
after self
, auto-dereferences self
, so this is the dereference of & pointer
that the error mentions.
Now ownership of thingies is the part that you cannot move out of
the dereference:
let widget = Widget::new(); // widget owns the unique pointer to self
let wotsits = widget.somethings(); // if this worked, ownership of
// unique pointer to thingies would be
// moved to wotsits
You could borrow a reference to thingies instead:
fn somethings<'a>(&'a self) -> &'a~[int] {
&self.thingies
}
or explicitly return a copy of thingies
fn somethings(&self) -> ~[int] {
self.thingies.clone()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With