根据this answer到this 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 */ >}`?
impl Component
作为返回类型基本上是T where T: Component
,其中T
由函数本身而不是调用者选择。
T
可以是Kind
,T
可以是Location
,但T
不能同时出现。
两种解决方案
Box<dyn Component>
并返回Box::new(Kind{})
或Box::new(Location{})
。缺点是它会导致堆分配。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
。编译器必须知道在编译时在堆栈上保留多少空间。正如链接的答案所提到的,如果具体的返回类型是有条件的,那么直到运行时才能知道所需的空间量。这就是答案所指的:
它确实有局限性,例如当具体的返回类型是有条件的时候它不能被使用。在这些情况下,您需要使用下面的特征对象答案。
如果要有条件地返回Kind
或Location
,您应该使用该答案中显示的函数的第二种形式。在这种情况下,Kind
或Location
将在堆而不是堆栈上创建;堆栈将包含拥有该堆引用的Box
,而Box
是一种在编译时已知大小的类型。