首页 > 解决方案 > 关联类型超特征的别名

问题描述

我有以下特点:

use std::ops::Index;

trait Map: Index<<Self as Map>::Key> {
    type Key;
}

Index有关联的类型Output。我在语义上想要这种类型,但我不喜欢Output我的 API 中的名称。因此,我想为该类型添加一个别名。

我试过这个(普通类型别名的语法相同):

trait Map: Index<<Self as Map>::Key> {
    type Key;
    type Value = <Self as Index<Self::Key>>::Output;
}

但是,这会导致错误:

error[E0658]: associated type defaults are unstable (see issue #29661)
 --> src/main.rs:9:9
  |
9 |         type Value = <Self as Index>::Output;
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

跟踪问题中,我可以得知此语法显然用于可被实现者覆盖的关联类型。但我不希望实现者覆盖这种类型,我一直希望Map::Value == Map::Output.

这有可能吗?

标签: rust

解决方案


相关的项目 RFC指出:

特征的类型参数可以是“输入”或“输出”:

  • 输入。“输入”类型参数用于确定使用哪个 impl。

  • 输出。“输出”类型参数由 impl 唯一确定,但在选择 impl 时不起任何作用。

RFC 还通过以下方式阐明了特征匹配:

  • 将所有特征类型参数视为输入类型,以及
  • 提供关联类型,即输出类型。

从这些描述中可以清楚地看出,关联类型在设计上由 控制impl,因此不可能阻止实现者覆盖该类型。

获得对实现者某种形式的控制的一种解决方法可能是定义一个使用关联类型的默认方法,例如:

pub trait Map: Index<<Self as Map>::Key> {
    type Key;
    type Value = <Self as Index<<Self as Map>::Key>>::Output;

    #[doc(hidden)]
    fn invalid_operation() -> Option<&'static <Self as Index<<Self as Map>::Key>>::Output> {
        None
    }
}

现在对于实现者来说更不可能简单地覆盖默认Value类型,因为默认方法invalid_operation不再类型检查。

还要注意doc(hidden)从文档中删除默认方法的功能。

可以选择隐藏的方法名称来传达一些信息。对于上面的示例,实现者收到错误消息:

 error[E0399]: the following trait items need to be reimplemented as `Value` was overridden: `invalid_operation`

如您所知,在当前稳定的 Rust 中不允许分配默认关联类型,必须使用每晚版本,并且必须启用该功能:

#![feature(associated_type_defaults)]

推荐阅读