如何为我不拥有的类型实现我不拥有的特征?

Posted

技术标签:

【中文标题】如何为我不拥有的类型实现我不拥有的特征?【英文标题】:How do I implement a trait I don't own for a type I don't own? 【发布时间】:2014-10-14 07:28:53 【问题描述】:

我想为Vec 实现Shl 特征,代码如下。这将使vec << 4 之类的事情成为可能,这对vec.push(4) 来说是很好的糖。

use std::ops::Shl;

impl<T> Shl<T> for Vec<T> 
    type Output = Vec<T>;

    fn shl(&self, elem: &T) -> Vec<T> 
        self.push(*elem);
        *self
    


fn main() 
    let v = vec![1, 2, 3];
    v << 4;

编译失败并出现以下错误:

无法提供扩展实现,其中 trait 和类型都未在此 crate 中定义 [E0117]

类型参数T必须用作某些本地类型的类型参数(例如MyStruct&lt;T&gt;);类型参数只能实现当前 crate 中定义的特征 [E0210]

据我了解,我必须修补 stdlib,更具体地说是 collections::vec 板条箱。是否有其他方法可以更改此代码以成功编译?

【问题讨论】:

这在设计上是不可能的。 【参考方案1】:

虽然您不能完全做到这一点,但通常的解决方法是将您想要的类型包装在您自己的类型中并在其上实现特征。

use somecrate::FooType;
use somecrate::BarTrait;

struct MyType(FooType);

impl BarTrait for MyType 
    fn bar(&self) 
        // use `self.0` here
    

【讨论】:

附录:实现 Deref trait 以避免每次都输入 &lt;MyType&gt;.0.foo 这在 2020 年仍然有效吗? @max 是的。这种“限制”是使 rust 成为如此好的语言的核心因素之一。所以这在 2020 年仍然有效,并且在 Rust 版本 1 中可能永远有效。【参考方案2】:

这将使vec &lt;&lt; 4 之类的事情成为可能,这对vec.push(4) 来说是很好的糖。

虽然可以做到,但一般是bad idea来实现一个意外语义的算子。

以下是如何做到这一点的示例:

use std::ops::Shl;

struct BadVec<T>(Vec<T>);

impl<T> Shl<T> for BadVec<T> 
    type Output = BadVec<T>;

    fn shl(mut self, elem: T) -> Self::Output 
        self.0.push(elem);
        self
    


fn main() 
    let mut v = BadVec(vec![1, 2, 3]);
    v = v << 4;
    assert_eq!(vec![1, 2, 3, 4], v.0)

如果你实现DerefDerefMut):

use std::ops::Deref, DerefMut;

impl<T> Deref for BadVec<T> 
    type Target = Vec<T>;

    fn deref(&self) -> &Self::Target 
        &self.0
    


impl<T> DerefMut for BadVec<T> 
    fn deref_mut(&mut self) -> &mut Self::Target 
        &mut self.0
    

你可以调用Vec方法:

fn main() 
    let mut v = BadVec(vec![1, 2, 3]);
    v = v << 4;
    v.truncate(2);
    assert_eq!(2, v.len());


看看newtype_derive crate,它可以为你生成一些样板代码。

【讨论】:

以上是关于如何为我不拥有的类型实现我不拥有的特征?的主要内容,如果未能解决你的问题,请参考以下文章

站点被克隆或部署到我不拥有的域

如何从 GitHub 仪表板中删除我不拥有的存储库

如何将 Ad Hoc 发送到我不拥有的设备

如何在序列化期间忽略我不拥有的子类的属性?

如何防止我不拥有的服务器在http请求中发送charset = UTF-8

如何为响应式网页设计准备 Inkscape SVG 文件?