从原始库"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>;

您不能重新实现在机箱外声明的类型。这是因为您在impl <'a> Token<'a>中添加的任何函数对于使用Token的任何其他板条箱来说都是未知的。通过重新实现,相同类型的实现在板条箱之间会有所不同,这就是为什么它是不允许的。

解决方案

这里正确的做法是用serialization_type函数声明一个特性,比如SerializationType,然后为Token实现SerializationType

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,
...
})
}
}

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

最新更新