基于广义自反的特化 • Lukas 的博客

几周前,dtolnay 介绍了基于自动引用(autoref)的特化概念,使其在稳定的 Rust 中实现类似特化的行为成为可能。该技术初始描述存在一些局限性,但通过引入两个关键变化,采用的自动解引用(autoderef)基特化版本比原始版本更通用,可用于更广泛的情况。

关键要点

  • 使用自动解引用(autoderef)代替自动引用(autoref)以使用任意多个特化级别。
  • 使用简单的包装类型(如struct Wrap<T>(T);)来避免与现有引用的泛型实现冲突。

前言
这里描述的采用版本不能解决基于自动引用特化的主要局限性,即泛型上下文中的特化。对于这类破坏参数性的情况,仍需要“真正的”特化。同时感谢 dtolnay 提出并公开描述这个巧妙的想法。

快速回顾:方法解析
“方法解析”是编译器确定方法调用表达式细节的过程,包括确定调用哪个方法以及如何强制接收者类型与方法的self类型匹配。基于自动引用的特化利用方法解析优先选择接收者类型强制转换较少的方法这一事实,通过自动引用强制转换来实现。这种方式不受限于 RFC 1210 中提出的特化要求,即一个实现必须比另一个更具体。

使用自动解引用进行≥两个特化级别
dtolnay 的原始示例使用两个特化级别,但有时需要三个或更多级别。通过使用自动解引用,可调整特化级别顺序,使更高优先级的实现在Self类型中有更多的引用。但要注意方法调用接收器的引用数量应与最高优先级方法中的self类型的引用数量相同,否则会导致奇怪的错误。

避免与其他泛型实现冲突
在使用有用的 trait(如StringDisplay)时,可能会与std中的其他 trait 的泛型实现产生干扰。通过使用包装类型(如struct Wrap<T>(T);),可以避免这种干扰,从而控制Wrap实现的 trait。

技术总结
假设有序列表有 N 组类型(“特化级别”),要使方法调用通过包含接收者类型的第一个特化级别进行调度,需创建struct Wrap<T>(T)类型,为每个特化级别创建相应的 trait 和实现,在方法调用时将接收者类型用( ⟨refs⟩ Wrap<⟨receiver⟩> ).method()包裹。

结论
自动解引用基特化比原始描述更通用,但仍存在局限性,主要在与宏结合使用时非常有用,在一般情况下过于有限和繁琐。Rust 仍需要一个合适的“特化解决方案”。作者在domsl库中使用了自动解引用基特化。

阅读 37
0 条评论