首页 > 解决方案 > 从原始库`use super`重构impl

问题描述

我仍在学习 Rust,并尝试rust-cssparser重新使用源库中定义的 impl,但得到编译错误,cannot define inherent impl for a type outside of the crate where the type is defined. 当然,图书馆使用use super::Token;,但我需要use cssparser::{ Token };,并且不知道如何解决。https://github.com/servo/rust-cssparser/blob/master/src/serializer.rs#L503-L552

摘抄:

impl<'a> Token<'a> {
    /// Categorize a token into a type that determines when `/**/` needs to be inserted
    /// between two tokens when serialized next to each other without whitespace in between.
    ///
    /// See the `TokenSerializationType::needs_separator_when_before` method.
    pub fn serialization_type(&self) -> TokenSerializationType {
        use self::TokenSerializationTypeVariants::*;
        TokenSerializationType(match *self {
            Token::Ident(_) => Ident,
            Token::AtKeyword(_) | Token::Hash(_) | Token::IDHash(_) => AtKeywordOrHash,
            ...
        })
    }
}

基于帮助note: define and implement a trait or new type instead和一些搜索,我在下面尝试了几个变体,但我没有深入了解编译错误的杂草。谢谢你的帮助。

use cssparser::{
    Token as Tkn,
  // Token
};

// struct Token<'a>(Tkn<'a>); // requires changing lots of refs
type Token<'a> = Tkn<'a>;

标签: rust

解决方案


您不能重新实现已在您的 crate 之外声明的类型。这是因为任何impl <'a> Token<'a>其他使用Token. 通过重新实现,相同类型的实现在 crate 之间会有所不同,这就是不允许这样做的原因。

解决方案

正确的做法是SerializationTypeserialization_type函数声明一个特征,然后实现SerializationTypefor Token

pub trait SerializationType<'a> {
    fn serialization_type(&self) -> TokenSerializationType;
}

impl<'a> SerializationType<'a> for Token<'a> {
    fn serialization_type(&self) -> TokenSerializationType {
        use self::TokenSerializationTypeVariants::*;
        TokenSerializationType(match *self {
            Token::Ident(_) => Ident,
            Token::AtKeyword(_) | Token::Hash(_) | Token::IDHash(_) => AtKeywordOrHash,
            ...
        })
    }
}

替代解决方案

另一种解决方案是创建一个新类型。请注意,别名类型不会创建新类型,因此会触发相同的错误。

pub type CustomToken<'a> = Token<'a>;

您应该封装Token<'a>到一个结构中,然后实现该结构:

struct CustomToken<'a>(Token<'a>);

impl <'a> CustomToken<'a> {
    fn serialization_type(&self) -> TokenSerializationType {
        use self::TokenSerializationTypeVariants::*;
        TokenSerializationType(match *self {
            Token::Ident(_) => Ident,
            Token::AtKeyword(_) | Token::Hash(_) | Token::IDHash(_) => AtKeywordOrHash,
            ...
        })
    }
}

在我看来,基于特征的解决方案更好。


推荐阅读