如何在自定义类型中实现fmt::Display?

4

我有一个自定义类型:

pub type Address = [u8; 32];

我尝试为这种类型实现fmt::Display:

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let public_key = sr25519::Public::from_raw(self);
        let address = public_key.to_ss58check();
        write!(f,"{}",address)
    }
}

但是我遇到了这个编译错误:

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> core/linix-primitives/src/lib.rs:122:1
    |
122 | impl fmt::Display for Address {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate

我理解要实现一个特质,我需要有以下两者之一:在本地定义type或者在本地定义trait

好的,我已经在本地定义了该类型:

pub type Address = [u8; 32];

那么我为什么会得到编译错误?
1个回答

6
问题在于以下代码并没有声明一个新类型:
pub type Address = [u8; 32];

但是它实际上更像一个 C 语言风格的 typedef,即类型别名。这意味着您的代码会被转换成以下内容:

impl fmt::Display for [u8; 32] {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let public_key = sr25519::Public::from_raw(self);
        let address = public_key.to_ss58check();
        write!(f,"{}",address)
    }
}

这里,[u8; 32]不是一个本地类型。你可能想要使用所谓的新类型模式。如果你的类型可能有一些填充,你可能需要添加一个#[repr]属性。


是的,看起来 repr(transparent) 就是我需要的。 - Nulik
@Nulik..或者你可以使用所谓的“newtype”模式,通过它你可以实现任何类型的特性。 - Peter Varo
嗯,repr(transparrent)不起作用了,我得到了这个错误:期望32个元素的数组,但发现了结构体Address - Nulik
1
你可能想要在那里添加一个 #[repr(transparent)],但这是一个不好的建议。除非进行像 mem::transmute 这样的操作,否则几乎没有人会想使用布局表示。关于此建议的后果,请参见 repr(transparent) does not allow a struct containing an array to be treated like an array - Shepmaster
@hellow @shepmaster 我加入了建议的更改,我已经很久没有接触C语言了,所以我忘记了typedef。我建议添加一个#[repr(transparent)],因为在编写时似乎有可能存在填充项,所以我打算通过它来节省一些空间,但我想编译器通常知道得更好。 - Optimistic Peach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接