Как мне вернуть принадлежащий массив из функции?
Я новичок в Rust, пытающийся понять язык, играя с ним. Я столкнулся с некоторыми проблемами при попытке вернуть массив из функции:
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();
}
Это, конечно, не компилируется с этой ошибкой:
pointers.rs:11:8: 11:21 error: cannot move out of dereference of & pointer
pointers.rs:11 self.thingies
В случае, если этот пример кода выглядит не в своем роде, все, что я пытаюсь сделать, это извлечь массив из реализованной структуры. Заимствованный указатель не важен, просто я пытаюсь сохранить данные.
Любые советы о том, как правильно извлечь мой массив?
Кстати, я использую Rust 0.8
3 ответа
Причина, по которой ваш код не компилируется, заключается в том, что уникальный указатель ~
может иметь только одного владельца. Компилятор не позволяет вам писать подверженный ошибкам код. Вы можете либо принять решение вернуть копию штук, ссылку на штук или часть штук (которая является ссылкой на векторные данные или их сегмент).
Копировать решение
struct Widget {
thingies: ~[int]
}
impl Widget {
fn new() -> Widget {
Widget { thingies: ~[4, 8, 15, 16, 23, 42] }
}
fn somethings(&self) -> ~[int] {
self.thingies.clone()
}
}
Эталонное решение
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
}
}
Раствор среза
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()
}
}
Чтобы понять референсные и срезовые решения, вам необходимо понять, что 'a
означает: это указывает на всю жизнь, и &'a
это способ сказать компилятору, что ссылка никогда не должна переживать объект, на который она ссылается, который в данном случае является виджетом.
Эти решения также имеют некоторые ограничения: вы не можете изменять объект, на который вы в данный момент ссылаетесь, потому что это открывает возможность того, что ссылки становятся недействительными.
Конечно, вы можете изменить вещи, если вы вернете изменчивую ссылку. Будет записана изменяемая ссылка со временем жизни &'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
}
}
Заметьте, я считаю, что в Rust 0.8 нужно написать &'self
вместо &'a
потому что время жизни с пользовательскими именами еще не было поддержано. Я также написал это в 0,9.
Редактировать: удалены избыточные объявления времени жизни.
=== РЕДАКТИРОВАТЬ ===
в Rust 1 конюшне, ~[T]
стал Vec<T>
, но (кроме синтаксиса) применима та же проблема, поскольку у Vec все еще есть уникальный владелец. В двух словах, somethings
имеет только ссылку на себя и (посредством ссылки) не может стать владельцем thingies
, Ссылка игровой площадки на версию Rust 1 здесь: https://play.rust-lang.org/?gist=50ec1acdc684e53fd5f9&version=stable.
Модель владения в Rust весьма важна для языка, поэтому для получения дополнительной информации я бы посоветовал взглянуть на великолепную официальную документацию по владению и заимствованию.
=== КОНЕЦ РЕДАКТИРОВАНИЯ ===
В Русте .
после self
авто-разыменования self
так что это dereference of & pointer
что ошибка упоминает.
Теперь владение вещами - это та часть, которую вы cannot move out of
разыменование:
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
Вместо этого вы можете позаимствовать ссылку на чтоли:
fn somethings<'a>(&'a self) -> &'a~[int] {
&self.thingies
}
или явно вернуть копию штуковин
fn somethings(&self) -> ~[int] {
self.thingies.clone()
}
Вы не можете выйти из заимствованного указателя, как объясняется в других ответах. Но вы можете пройти self
по значению или по собственному указателю, тогда вы сможете вернуть собственный вектор:
struct Widget {
thingies: ~[int]
}
impl Widget {
fn somethings(self) -> ~[int] {
self.thingies
}
}