Rust不会让我从匹配中返回一个类型的实例,一直在想我正在尝试返回一个值

问题描述 投票:-1回答:2

根据this answerthis questions,我需要做以下操作来返回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 */ >}`?
rust
2个回答
2
投票

impl Component作为返回类型基本上是T where T: Component,其中T由函数本身而不是调用者选择。

T可以是KindT可以是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
投票

编译器必须知道在编译时在堆栈上保留多少空间。正如链接的答案所提到的,如果具体的返回类型是有条件的,那么直到运行时才能知道所需的空间量。这就是答案所指的:

它确实有局限性,例如当具体的返回类型是有条件的时候它不能被使用。在这些情况下,您需要使用下面的特征对象答案。

如果要有条件地返回KindLocation,您应该使用该答案中显示的函数的第二种形式。在这种情况下,KindLocation将在堆而不是堆栈上创建;堆栈将包含拥有该堆引用的Box,而Box是一种在编译时已知大小的类型。

© www.soinside.com 2019 - 2024. All rights reserved.