在我的简短Rust经历中,我多次遇到这种模式,我不确定我解决它的方式是否足够......
让我们假设我有一些看起来像这样的特征:
trait Container {
type Item;
fn describe_container() -> String;
}
一些实现这个特性的结构:
struct ImAContainerType;
struct ImAnItemType;
impl Container for ImAContainerType {
type Item = ImAnItemType;
fn describe_container() -> String { "some container that contains items".to_string() }
}
这可能是一个容器,它知道它包含的项目类型,如本例所示,或者,作为另一个例子,知道应该返回什么类型的响应的请求等。
现在我发现自己处于某种情况,当我需要实现一个带有项(相关类型)的函数并调用容器的静态函数(父特征)时。这是第一次天真的尝试:
fn describe_item_container<C: Container>(item: C::Item) -> String {
C::describe_container()
}
这不能编译,因为关联类型不是单射的,Item
可能有几个Container
s,所以整个情况都不明确。我需要以某种方式提供实际的Container
类型,但不提供任何容器数据。当我调用这个函数时,我可能根本没有容器数据本身!
在寻找解决方案时,我找到了std::marker::PhantomData的文档。它说:
PhantomData允许您描述一个类型就像存储类型T的值一样,即使它没有。
这必须是Rust替换Haskell's Proxy type,对吧?让我们尝试使用它:
fn describe_item_container<C: Container>(container: PhantomData<C>, item: C::Item) -> String {
C::describe_container()
}
let s = describe_item_container(PhantomData::<PhantomData<ImAContainerType>>, ImAnItemType);
println!("{}", s);
编译......错误:
error[E0277]: the trait bound `std::marker::PhantomData<ImAContainerType>: Container` is not satisfied
我问#rust-beginners
并得到回复:PhantomData
根本不应该以这种方式使用!另外,我得到一个建议,只需创建从Item
到Container
的向后关联类型链接。像这样:
trait Item {
type C: Container;
}
fn describe_item_container<I: Item>(item: I) -> String {
I::C::describe_container()
}
它应该可以工作,但会使事情变得更复杂(特别是对于可以将物品放置在不同容器类型中的情况)......
经过更多的实验,我做了以下更改,所有内容都编译并正常运行:
let s = describe_item_container(PhantomData::<ImAContainerType>, ImAnItemType);
println!("{}", s);
更改为::<PhantomData<ImAContainerType>>
至::<ImAContainerType>
。
它有效,但现在我完全糊涂了。这是使用PhantomData
的正确方法吗?为什么它可以工作?是否有其他更好的方法为Rust中的函数提供仅类型参数?
编辑:我的示例中有一些过度简化,因为在特定情况下,调用ImAContainerType::describe_container()
会更容易。这是一些more complicated case,当函数实际上使用Item
执行某些操作时,仍然需要容器类型信息。
答案 0 :(得分:7)
如果要将类型参数传递给函数,则可以执行此操作。您不必将其遗漏以进行推断。
这是它查找第二个示例(playground)的方式:
@HostListener('window:resize', ['$event'])
onResize(event) {
}