如何为 WinRT 集合接口创建现成的集合?
除了自己实现 COM 接口之外,windows crate 还为常见的 WinRT 集合接口提供了现成的集合实现。实现 WinRT 集合接口可能非常具有挑战性,因此在许多情况下,这应该能为您省去很多工作。需要使用 implement
功能才能使用这些现成的实现。
让我们考虑几个示例。WinRT 集合接口都定义在 Foundation::Collections
模块中,因此我们首先添加对 windows
crate 的依赖,并包含 Foundation_Collections
功能
[dependencies.windows]
version = "0.52"
features = [
"implement",
"Foundation_Collections",
]
创建集合就像在现有 Vec
或 BTreeMap
上使用 TryFrom
特征一样简单,具体取决于集合的类型
WinRT 接口 | 来自 |
---|---|
IIterable<T> | Vec<T::Default> |
IVectorView<T> | Vec<T::Default> |
IMapView<K, V> | BTreeMap<K::Default, V::Default> |
因此,如果您需要 i32
值的 IIterable
实现,您可以按如下方式创建它
use windows::{core::*, Foundation::Collections::*}; fn main() -> Result<()> { let collection = IIterable::<i32>::try_from(vec![1, 2, 3])?; for n in collection { println!("{n}"); } Ok(()) }
生成的 collection
将实现所有专用的 IIterable<i32>
方法。
您是否注意到上表中的 T::Default
?挑战在于,当 WinRT 集合包含可为空类型时(与 i32
不同),集合必须必然支持能够表达此情况的后端实现。对于此类可为空或引用类型,Default
关联类型只是将 T
替换为 Option<T>
。
让我们考虑一个稍微更刻意的例子。在这里,我们将创建一个 IMapView
,其中字符串用作键,接口用作值。WinRT 字符串不可为空,但接口可为空。WinRT 字符串在 windows
crate 中由 HSTRING
表示,对于接口,我们将仅使用 IStringable
实现
#![allow(unused)] fn main() { use windows::Foundation::*; #[implement(IStringable)] struct Value(&'static str); impl IStringable_Impl for Value { fn ToString(&self) -> Result<HSTRING> { Ok(self.0.into()) } } }
我们现在可以按如下方式创建 std
集合
#![allow(unused)] fn main() { use std::collections::*; let map = BTreeMap::from([ ("hello".into(), Some(Value("HELLO").into())), ("hello".into(), Some(Value("WORLD").into())), ]); }
Rust 编译器自然会推断出确切的类型:BTreeMap<HSTRING, Option<IStringable>>
。
最后,我们可以使用 TryInto
特征将该 BTreeMap
包装在 WinRT 集合中,如下所示
#![allow(unused)] fn main() { let map: IMapView<HSTRING, IStringable> = map.try_into()?; for pair in map { println!("{} - {}", pair.Key()?, pair.Value()?.ToString()?); } }