Rust не позволяет мне возвращать экземпляр типа из совпадения, продолжает думать, что я пытаюсь вернуть значение - PullRequest
0 голосов
/ 05 апреля 2019

Согласно этому ответу на этим вопросам Мне нужно сделать следующее, чтобы вернуть экземпляр Trait:

trait Shader {}

struct MyShader;
impl Shader for MyShader {}

struct GraphicsContext;

impl GraphicsContext {
    fn create_shader(&self) -> impl Shader {
        let shader = MyShader;
        shader
    }
}

но когда я пытаюсь это сделать:

pub trait Component { }

struct Kind {}

struct Location {}

impl Component for Kind {}

impl Component for Location {}

pub fn get(comp_name: &String) -> impl Component {
    match comp_name.as_ref() {
        "kind"      => Kind,
        "location"  => Location
    }
}

Я просто получаю ошибки:

ошибка [E0423]: ожидаемое значение, найдено struct Kind -> src / main.rs: 17: 24

   |
17 |         "kind"      => Kind,
   |                        ^^^^ did you mean `Kind { /* fields */ }`?

ошибка [E0423]: ожидаемое значение, найдено struct Location -> src / main.rs: 18: 24

   |
18 |         "location"  => Location
   |                        ^^^^^^^^ did you mean `Location { /* fields */ >}`?

Ответы [ 2 ]

2 голосов
/ 06 апреля 2019

То, что impl Component в качестве возвращаемого типа, в основном равно T where T: Component, где T выбирается самой функцией, а не вызывающей стороной.

T может быть Kind,T может быть Location, но T не может быть одновременно одновременно.

Два решения:

  1. Динамически: вернуть Box<dyn Component> ивозврат Box::new(Kind{}) или Box::new(Location{}).Недостатком является то, что он вызывает выделение кучи.

  2. Статически, возвращая enum:

enum KindOrLocation {
    Kind(Kind),
    Location(Location),
}

, чтобы сделать это пригодным для использованиякак Component, вы можете реализовать Deref<Target = dyn Component>:

impl Deref for KindOrLocation {
    type Target = dyn Component + 'static;
    fn deref(&self) -> &Self::Target {
        match self {
            KindOrLocation::Kind(x) => x,
            KindOrLocation::Location(x) => x,
        }
    }
}

Недостатком здесь является то, что вы должны написать этот шаблонный код.


Кстати:

  • Если вы определяете структуру с помощью {}, как struct Kind {}, вы создаете ее объект, записывая Kind{}, а не просто Kind.
  • . Вам нужно обработать_ дело в вашем матче: _ => panic!() или что-то еще.
  • Не берите &String, а вместо этого &str.Тогда это работает для и &String и &str.
0 голосов
/ 05 апреля 2019

Компилятор должен знать, сколько места нужно зарезервировать в стеке во время компиляции. Как упоминается в связанном ответе, если конкретный тип возврата является условным, то объем пространства, который может потребоваться, не может быть известен до времени выполнения. Вот к чему относится этот бит ответа:

У него есть ограничения, такие как [...], его нельзя использовать, когда конкретный тип возврата условна. В этих случаях вам нужно использовать ответ объекта черты ниже.

Вам следует использовать вторую форму функции, показанной в этом ответе, если вы хотите условно вернуть либо Kind, либо Location. В этом случае Kind или Location будут созданы в куче, а не в стеке; стек будет содержать Box, которому принадлежит эта ссылка в куче, а Box - это тип, размер которого известен во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...