使用Iced的过程中理解Rust的关联类型
关联类型(Associated type)
关联类型是Rust为了解决类型参数(type parameter)之间的依赖关系而引入的。清楚的解释引入动机的文章就是 RFC095 。
同时,这篇文章详细说明了如何引用关联类型。
一个实际的例子
我们在使用Iced(一个跨平台的GUI库)开发一个自定义样式的button的时候, 遇到了关联类型。
以下代码创建一个button对象,宽度80,高50,样式怎么输入呢?
1 |
|
看看这个style方法的签名。
1 |
|
style方法是Button结构体的一个关联方法。
Button结构体是一个组件,它有两个类型参数,Message和Renderer。
其中Renderer
类型参数的Bound在where中明确
- Renderer: crate::Renderer 需要实现
crate::Renderer
trait. - Renderer::Theme: StyleSheet 并且该
crate::Renderer
trait的Theme
关联类型需要实现StyleSheet
trait.
crate::Renderer
trait如下,有一个Theme
关联类型
1 |
|
还是回到这个style方法pub fn style(mut self, style: <Renderer::Theme as StyleSheet>::Style) -> Self
。
这个方法的入参style的类型是<Renderer::Theme as StyleSheet>::Style
,这个PATH的前缀是
<Renderer::Theme as StyleSheet>
表示实现了Renderer trait的类型的Theme
关联类型
需要实现StyleSheet
trait。
因此<Renderer::Theme as StyleSheet>::Style
完整的含义就是
- 某个渲染类型 SomeRenderer 实现了
crate::Renderer
trait. - 某个样式板类型 SomeThemeType 实现了
button::StyleSheet
。 - 且 SomeRenderer::Theme = SomeThemeType
<Renderer::Theme as StyleSheet>::Style
就是 SomeThemeType::Style = < ?? >.
因此style方法的入参的实际类型就是SomeStyleSheet::Style的实际类型。所以我们要找到SomeRenderer和SomeThemeType。
- 先看
crate::Renderer
trait的实现类型有那些,可以看到Renderer<B, T>
1
2
3
4
5
6
7impl<B, T> iced_native::Renderer for Renderer<B, T>
where
B: Backend,
{
type Theme = T;
...
...
这个结构体如下,
1 |
|
这个似乎就是我们要找的 SomeRenderer。但是这个Renderer<B, T>
有两个类型参数,第二个就是Theme类型参数。还是没有看到
这个类型参数具体的类型是什么。继续看哪里使用了这个带有类型参数的结构体Renderer<B, T>
。
1 |
|
这里看到声明了一个新的类型iced_wgpu::Renderer
,并且指定了Theme = iced_style::theme::Theme
。
这个新的类型在哪里使用了呢?
1 |
|
因此这个iced_wgpu::Renderer
就是我们要找的SomeRenderer,而SomeRenderer::Theme就是
iced_style::theme::Theme
就是我们要找的SomeThemeType。
- 接着看
iced_style::theme::Theme
类型如何实现button::StyleSheet
trait 从这里可以看到SomeThemeType::Style = iced_style::theme::Button
因此style方法的入参是iced_style::theme::Button, 是一个枚举类型。
1 |
|
从定义可以看出,如果我们要实现自定义的样式就需要使用Button::Custom(Box::new(??)).
而button::StyleSheet<Style = Theme>
类型意思是某类型实现了button::StyleSheet
trait,
并且关联类型Style = iced_style::theme::Theme.
所以我们可以写一个自定义的button样式了。
1 |
|
style方法的入参就是Button::Custom(Box::new(ButtonStyle{}))
。
最后style方法的使用如下
1 |
|
关于Iced
Iced
使用的Elm模型非常容易使用。我用它实现一个简单的计算器。
总结
关联类型是Rust非常重要的特性。如果不深入理解的话,编译的错误信息都看不明白。