Ответ 1
Это сложная точка объектов-признаков, вам нужно четко указать, кто владеет базовым объектом.
Действительно, когда вы используете черту как тип, базовый объект должен быть где-то сохранен, поскольку объекты-объекты на самом деле ссылаются на объект, реализующий данный признак. Вот почему у вас не может быть голый MyTrait
как тип, он должен быть либо ссылкой &MyTrait
, либо поле Box<MyTrait>
.
Со ссылками
Первый метод, который вы пробовали, был с ссылкой, и компилятор жаловался на отсутствующий спецификатор времени жизни:
struct Bar {
foo : &Foo,
}
Проблема заключается в том, что ссылка не владеет базовым объектом, а другой объект или область должны владеть им где-то: вы заимствуете ее только. И, таким образом, компилятору нужна информация о том, как долго эта ссылка будет действительной: если основной объект был уничтожен, ваш экземпляр Bar имел бы ссылку на свободную память, что запрещено!
Идея здесь состоит в том, чтобы добавить времена жизни:
struct Bar<'a> {
foo : &'a (Foo + 'a),
}
Что вы здесь говорите компилятору: "Мой объект Bar не может пережить ссылку Foo внутри него". Вы должны указать время жизни два раза: один раз для времени жизни ссылки и один раз для объекта-объекта, потому что черты могут быть реализованы для ссылок, а если базовый объект является ссылкой, вы также должны указать его время жизни.
В специальном случае записывалось бы:
struct Bar<'a> {
foo : &'a (Foo + 'static),
}
В этом случае 'static
требует, чтобы базовый объект должен быть реальной структурой или ссылкой &'static
, но другие ссылки не будут разрешены.
Кроме того, чтобы создать свой объект, вам нужно будет дать ссылку на другой объект, который вы храните самостоятельно.
В итоге вы получите что-то вроде этого:
trait Foo {}
struct MyFoo;
impl Foo for MyFoo {}
struct Bar<'a> {
foo: &'a (Foo + 'a),
}
impl<'a> Bar<'a> {
fn new(the_foo: &'a Foo) -> Bar<'a> {
Bar { foo: the_foo }
}
fn get_foo(&'a self) -> &'a Foo {
self.foo
}
}
fn main() {
let myfoo = MyFoo;
let mybar = Bar::new(&myfoo as &Foo);
}
С коробками
Коробка, напротив, владеет своим контентом, таким образом, он позволяет вам передать право собственности на базовый объект на вашу структуру Bar. Тем не менее, поскольку этот базовый объект может быть ссылкой, вам также нужно указать время жизни:
struct Bar<'a> {
foo: Box<Foo + 'a>
}
Если вы знаете, что базовый объект не может быть ссылкой, вы также можете написать:
struct Bar {
foo: Box<Foo + 'static>
}
и проблема времени жизни полностью исчезает.
Таким образом, построение объекта аналогично, но проще, поскольку вам не нужно самостоятельно хранить базовый объект, он обрабатывается полем:
trait Foo {}
struct MyFoo;
impl Foo for MyFoo {}
struct Bar<'a> {
foo: Box<Foo + 'a>,
}
impl<'a> Bar<'a> {
fn new(the_foo: Box<Foo + 'a>) -> Bar<'a> {
Bar { foo: the_foo }
}
fn get_foo(&'a self) -> &'a Foo {
&*self.foo
}
}
fn main() {
let mybar = Bar::new(box MyFoo as Box<Foo>);
}
В этом случае версия 'static
будет:
trait Foo {}
struct MyFoo;
impl Foo for MyFoo {}
struct Bar {
foo: Box<Foo + 'static>,
}
impl Bar {
fn new(the_foo: Box<Foo + 'static>) -> Bar {
Bar { foo: the_foo }
}
fn get_foo<'a>(&'a self) -> &'a Foo {
&*self.foo
}
}
fn main() {
let mybar = Bar::new(box MyFoo as Box<Foo>);
let x = mybar.get_foo();
}
С открытым значением
Чтобы ответить на ваш последний вопрос:
Что подразумевает удаление и и просто использование self?
Если метод имеет такое же определение:
fn unwrap(self) {}
Это означает, что он будет потреблять ваш объект в процессе, и после вызова bar.unwrap()
вы больше не сможете использовать bar
.
Это процесс, который обычно используется для возврата права собственности на данные, принадлежащие вашей структуре. Вы встретите много функций unwrap()
в стандартной библиотеке.