IT TIP

구조체의 특성에 대한 참조

itqueen 2021. 1. 6. 20:34
반응형

구조체의 특성에 대한 참조


나는 특성이있다 Foo

pub trait Foo {
   fn do_something(&self) -> f64;
}

그 특성을 참조하는 구조체

pub struct Bar {
   foo: Foo,
}

내가 컴파일하려고

error: reference to trait `Foo` where a type is expected; try `Box<Foo>` or `&Foo`

구조체를 다음으로 변경

struct Bar {
   foo: &Foo,
}

말해 error: missing lifetime specifier

정의를 다음으로 변경

struct Bar {
   foo: Box<Foo>,
}

컴파일 — 예!

그러나, 나는 반환하는 기능을 할 때 foobar- 같은 :

impl Bar {
    fn get_foo(&self) -> Foo {
        self.foo
    }
}

그럼 분명히 bar.fooA는 Box<Foo>그렇게 예상대로 내가 얻을,error: reference to trait `Foo` where a type is expected; try `Box<Foo>` or `&Foo`

서명을 다음으로 변경

impl Bar {
    fn get_foo(&self) -> Box<Foo> {
        let this = *self;
        this.foo
    }
}

하지만 지금 error: cannot move out of dereference of `&`-pointer은 역 참조를 시도합니다 self.

다음으로 변경

impl Bar {
    fn get_foo(self) -> Box<Foo> {
        self.foo
    }
}

모두 좋다.

그래서....

  1. 왜하지 않는 &에서 bar구조체를 사용할 수 있습니까? 구조체에 메모리 레이아웃이 설정되어 있으므로 상자에 넣어야한다고 가정하고 있으므로 특성에 대한 포인터라고 말해야하는데 (얼마나 클지 알 수 없기 때문에) 컴파일러가 컴파일되지 않는 것을 제안하는 이유는 무엇입니까? ?
  2. 역 참조 self할 수없는 이유 get_foo()-내가 본 모든 예제는 빌린 self구문을 사용합니까?
  3. 제거 &하고 그냥 사용 하는 의미는 무엇입니까 self?

Rust를 배우는 것은 매혹적이지만 메모리 안전은 매혹적이며 위협적입니다!

다음을 컴파일하는 전체 코드 :

trait Foo {
    fn do_something(&self) -> f64;
}

struct Bar {
    foo: Box<Foo>,
}

impl Bar {
    fn get_foo(self) -> Box<Foo> {
        let foo = self.foo;
        foo.do_something();
        foo
    }
}

fn main() {}

이것은 트레이 트 객체의 까다로운 요점이며, 누가 기본 객체를 소유하는지에 대해 매우 명확해야합니다.

실제로 트레이 트를 유형으로 사용할 때 트레이 트 객체는 실제로 주어진 트레이 트를 구현하는 객체에 대한 참조이므로 기본 객체는 어딘가에 저장되어야합니다. 이것이 베어 MyTrait를 유형 으로 가질 수없는 이유 입니다. 참조 &MyTrait또는 상자 여야합니다 Box<MyTrait>.

참조 포함

시도한 첫 번째 방법은 참조를 사용하는 것이었고 컴파일러는 누락 된 수명 지정자에 대해 불평했습니다.

struct Bar {
   foo : &Foo,
}

문제는 참조가 기본 객체를 소유하지 않고 다른 객체 나 범위가 어딘가에이를 소유해야한다는 것입니다. 따라서 컴파일러는이 참조가 얼마나 오래 유효한 지에 대한 정보가 필요합니다. 기본 객체가 파괴되면 Bar 인스턴스가 해제 된 메모리에 대한 참조를 갖게되며 이는 금지됩니다!

여기서 아이디어는 수명을 추가하는 것입니다.

struct Bar<'a> {
   foo : &'a (Foo + 'a),
}

여기서 컴파일러에게 말하는 것은 "My 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);
}

상자 포함

A Box contrarily owns its content, thus it allows you to give ownership of the underlying object to your Bar struct. Yet, as this underlying object could be a reference, you need to specify a lifetime as well :

struct Bar<'a> {
    foo: Box<Foo + 'a>
}

If your know that the underlying object cannot be a reference, you can also write:

struct Bar {
    foo: Box<Foo + 'static>
}

and the lifetime problem disappears completely.

The construction of the object is thus similar, but simpler as you don't need to store the underlying object yourself, it is handled by the box :

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>);
}

In this case, the 'static version would be :

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();
}

With the bare value

To answer your last question :

Whats the implication of removing the & and just using self?

If a method has a definition like this :

fn unwrap(self) {}

It means it will consume your object in the process, and after calling bar.unwrap(), you won't be able to use bar any longer.

It is a process used generally to give back ownership of the data your struct owned. You'll meet a lot of unwrap() functions in the standard library.


To note for future reference: the syntax has changed from

struct Bar<'a> {
    foo: &'a Foo + 'a,
}

to

struct Bar<'a> {
    foo: &'a (Foo + 'a), // with parens
}

Per RFC 438

ReferenceURL : https://stackoverflow.com/questions/26212397/references-to-traits-in-structs

반응형