当特征和类型都不在此包中时提供实现

use*_*625 7 traits rust

我想为一个原始类型提供一个特征的实现ToHex(我没有定义serialize)u8:

impl ToHex for u8 {
    fn to_hex(&self) -> String {
        self.to_str_radix(16)
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我得到这个编译错误:

error: cannot provide an extension implementation where both trait and type are not defined in this crate
Run Code Online (Sandbox Code Playgroud)

我理解这个错误的原因及其逻辑,这是因为特征和原始类型都在我的代码外部.但是我该如何处理这种情况并提供ToHex实现u8呢?更一般地说,你如何处理这类问题,在我看来,这个问题必须是常见的,它应该是可能的,并且很容易扩展这样的类型?

Vla*_*eev 12

您应该使用newtype结构来执行此操作:

pub struct U8(pub u8)

impl ToHex for U8 {
    fn to_hex(&self) -> String {
        let U8(x) = *self;
        x.to_str_radix(16)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这确实意味着您应该u8进入U8需要执行此转换的位置:

let x: u8 = 127u8

// println!("{}", x.to_hex());   // does not compile
println!("{}", U8(x).to_hex());
Run Code Online (Sandbox Code Playgroud)

这在性能方面完全免费.

  • @ user3762625,它不是一个黑客,它实际上是唯一可行的方法.您不能将您不拥有的特征的特征实现添加到您不拥有的类型,并且没有解决方法而是newtypes. (3认同)

cra*_*ish 5

我意识到这已经快一年了,但是答案从未被接受,我想我已经找到了替代解决方案,我认为在这里记录一下是很好的。

为了通过特征扩展u8的功能,而不是尝试扩展ToHex,为什么不创建一个新特征?

trait MyToHex {
    fn to_hex(&self) -> String;
}

impl MyToHex for u8 {
    fn to_hex(&self) -> String {
        format!("{:x}", *self)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用

fn main() {
    println!("{}", (16).to_hex());
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处是您不必用新的多余数据类型包装每个u8变量。

缺点是您仍然不能在需要ToHex特性的外部函数(即std库,或者您无法控制的函数)中使用u8(在这种情况下,Vladimir Matveev的解决方案有效),但是从OP听起来像您要做的就是仅在代码内部扩展u8