繁体   English   中英

如何对此 Rust 特征使用相同的默认实现

[英]How can I use the same default implementation for this Rust trait

我想实现一个允许分配泛型类型的特征。 到目前为止,我已经对u32String类型进行了测试:

trait Test {
    fn test(&self, input: &str) -> Self;
}

impl Test for String {
    fn test(&self, input: &str) -> Self {
        input.parse().unwrap()
    }
}

impl Test for u32 {
    fn test(&self, input: &str) -> Self {
        input.parse().unwrap()
    }
}

fn main() {
    let mut var = 0u32;
    let mut st = String::default();

    var = var.test("12345678");
    st = st.test("Text");
    println!("{}, {}", var, st);
}

我知道这段代码并不完美,我应该使用Result返回而不是展开,但请把它放在一边,因为这是一个简单的例子。 u32String的实现完全相同,所以我想对两者都使用默认实现,而不是复制和粘贴代码。 我试过使用一个,但由于返回的类型Self在两者中都不同,编译器无法确定类型大小和错误。

在这种情况下,我该如何编写默认实现?

默认实现

默认实现需要以下Self边界:

  1. Self: Sized ,因为Self是从 function 返回的,将被放入调用者的堆栈中
  2. Self: FromStr因为您在input上调用parse()并期望它产生一个Self类型的值
  3. <Self as FromStr>::Err: Debug因为当你unwrap一个潜在的错误并且程序崩溃时 Rust 希望能够打印错误消息,这需要错误类型来实现Debug

全面实施:

use std::fmt::Debug;
use std::str::FromStr;

trait Test {
    fn test(&self, input: &str) -> Self
    where
        Self: Sized + FromStr,
        <Self as FromStr>::Err: Debug,
    {
        input.parse().unwrap()
    }
}

impl Test for String {}
impl Test for u32 {}

fn main() {
    let mut var = 0u32;
    let mut st = String::default();

    var = var.test("12345678");
    st = st.test("Text");
    println!("{}, {}", var, st);
}

操场


通用实现

通用的一揽子实现也是可能的,您可以在其中自动为满足特征界限的所有类型提供Test的实现:

use std::fmt::Debug;
use std::str::FromStr;

trait Test {
    fn test(&self, input: &str) -> Self;
}

impl<T> Test for T
where
    T: Sized + FromStr,
    <T as FromStr>::Err: Debug,
{
    fn test(&self, input: &str) -> Self {
        input.parse().unwrap()
    }
}

fn main() {
    let mut var = 0u32;
    let mut st = String::default();

    var = var.test("12345678");
    st = st.test("Text");
    println!("{}, {}", var, st);
}

操场


宏实现

这个实现,类似于默认实现,允许你选择哪些类型得到实现,但它也类似于通用实现,因为它不需要你用任何额外的 trait 边界修改 trait 方法签名:

trait Test {
    fn test(&self, input: &str) -> Self;
}

macro_rules! impl_Test_for {
    ($t:ty) => {
        impl Test for $t {
            fn test(&self, input: &str) -> Self {
                input.parse().unwrap()
            }
        }
    }
}

impl_Test_for!(u32);
impl_Test_for!(String);

fn main() {
    let mut var = 0u32;
    let mut st = String::default();

    var = var.test("12345678");
    st = st.test("Text");
    println!("{}, {}", var, st);
}

操场


主要区别

三种方法之间的主要区别:

  • 默认实现使特征边界成为方法签名所固有的,因此所有impl Test的类型都必须调整大小,并具有带有可调试错误类型的FromStr impl。
  • 默认实现允许您有选择地选择哪些类型获得Test实现。
  • 通用实现不会向 trait 方法的签名添加任何 trait 边界,因此更多种类的类型可能会实现该 trait。
  • 泛型实现会自动为所有满足边界的类型实现特征,如果有某些类型您不想实现特征,则不能选择性地“退出”泛型实现。
  • 宏实现不需要使用额外的特征边界修改特征方法签名,并允许您有选择地选择哪些类型得到实现。
  • 宏实现是一个宏,并且具有作为宏的所有缺点:难以读取、写入、维护、增加编译时间,并且宏对 static 代码分析器基本上是不透明的,这使得更难轻松地对代码进行类型检查。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM