简体   繁体   English

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

[英]Rust won't let me return an instance of a type from a match, keeps thinking I'm trying to return a value

According to this answer to this questions I need to do the following to return an instance of a Trait : 根据这个答案这个问题 ,我需要做下面的返回一个实例Trait

trait Shader {}

struct MyShader;
impl Shader for MyShader {}

struct GraphicsContext;

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

but when I try to do it: 但是当我尝试这样做时:

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

I just get errors: 我刚得到错误:

error[E0423]: expected value, found struct Kind --> src/main.rs:17:24 错误[E0423]:期望值,找到结构Kind -> src / main.rs:17:24

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

error[E0423]: expected value, found struct Location --> src/main.rs:18:24 错误[E0423]:期望值,找到结构Location -> src / main.rs:18:24

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

That impl Component as the return type is basically a T where T: Component , where the T is chosen by the function itself rather than by the caller. impl Component作为返回类型基本上是T where T: Component ,其中T由函数本身而不是调用方选择。

T can be Kind , T can be Location , but T can't be both at once. T可以是KindT可以是Location ,但T不能同时是两者。

Two solutions: 两种解决方案:

  1. Dynamically: Return a Box<dyn Component> and return Box::new(Kind{}) or Box::new(Location{}) . 动态地:返回Box<dyn Component>并返回Box::new(Kind{})Box::new(Location{}) The disadvantage is that it causes an heap allocation. 缺点是它会导致堆分配。

  2. Statically, by returning an enum : 静态地,通过返回一个enum

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

To make this usable as a Component , you can implement Deref<Target = dyn Component> : 要使其可用作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,
        }
    }
}

The disadvantage here is that you have to write this boilerplate code. 这里的缺点是您必须编写此样板代码。


By the way: 顺便说说:

  • If you define a struct with {} like struct Kind {} , you create an object of it by writing Kind{} , not just Kind . 如果您使用{}定义一个结构,例如struct Kind {} ,则可以通过编写Kind{}创建对象,而不仅仅是Kind
  • You need to handle the _ case in your match: _ => panic!() or something. 您需要在比赛中处理_情况: _ => panic!()
  • Don't take a &String , but take a &str instead. 不要使用&String ,而应使用&str Then it works for both &String and &str . 然后,它同时适用于&String&str

The compiler has to know how much room to reserve on the stack at compile time. 编译器必须知道在编译时要在堆栈上保留多少空间。 As the linked answer mentions, if the concrete return type is conditional, the amount of space that would be needed cannot be known until runtime. 如链接的答案所述,如果具体的返回类型是有条件的,则直到运行时才能知道所需的空间量。 That's what this bit of the answer is referring to: 这就是答案的含义:

It does have limitations, such as [...] it cannot be used when the concrete return type is conditional. 它的确有局限性,例如,当具体的返回类型是有条件的时,就不能使用它。 In those cases, you need to use the trait object answer below. 在这种情况下,您需要使用以下特征对象答案。

You should use the second form of the function shown in that answer if you want to conditionally return either a Kind or a Location . 如果要有条件地返回KindLocation则应使用该答案中显示的函数的第二种形式。 In that case, the Kind or the Location will be created on the heap instead of the stack; 在这种情况下,将在堆而不是堆栈上创建KindLocation the stack will contain a Box that owns that heap reference, and Box is a type whose size is known at compile time. 堆栈将包含一个Box拥有该堆参考,和Box是一个类型,其尺寸在编译时是已知的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM