简体   繁体   English

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

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

I want to implement a trait that allows assigning generic types.我想实现一个允许分配泛型类型的特征。 So far I have tested this for u32 and String types:到目前为止,我已经对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);
}

I know this code is not perfect, and I should be using a Result return instead of unwrapping, but please set this aside as this is a quick example.我知道这段代码并不完美,我应该使用Result返回而不是展开,但请把它放在一边,因为这是一个简单的例子。 The implementations for u32 and String are exactly the same, so I would like to use a default implementation for both instead of copying & pasting the code. u32String的实现完全相同,所以我想对两者都使用默认实现,而不是复制和粘贴代码。 I have tried using one, but as the returned type Self differs in both, compiler cannot determine the type size and errors.我试过使用一个,但由于返回的类型Self在两者中都不同,编译器无法确定类型大小和错误。

How could I write a default implementation in this case?在这种情况下,我该如何编写默认实现?

Default implementation默认实现

The following bounds on Self are required for the default implementation:默认实现需要以下Self边界:

  1. Self: Sized because Self is returned from the function and will be placed in the caller's stack Self: Sized ,因为Self是从 function 返回的,将被放入调用者的堆栈中
  2. Self: FromStr because you're calling parse() on input and expecting it to produce a value of type Self Self: FromStr因为您在input上调用parse()并期望它产生一个Self类型的值
  3. <Self as FromStr>::Err: Debug because when you unwrap a potential error and the program panics Rust wants to be able to print the error message, which requires the error type to implement Debug <Self as FromStr>::Err: Debug因为当你unwrap一个潜在的错误并且程序崩溃时 Rust 希望能够打印错误消息,这需要错误类型来实现Debug

Full implementation:全面实施:

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);
}

playground 操场


Generic implementation通用实现

A generic blanket implementation is also possible, where you automatically provide an implementation of Test for all types which satisfy the trait bounds:通用的一揽子实现也是可能的,您可以在其中自动为满足特征界限的所有类型提供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);
}

playground 操场


Macro implementation宏实现

This implementation, similar to the default implementation, allows you to pick which types get the implementation, but it's also similar to the generic implementation, in that it doesn't require you to modify the trait method signature with any additional trait bounds:这个实现,类似于默认实现,允许你选择哪些类型得到实现,但它也类似于通用实现,因为它不需要你用任何额外的 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);
}

playground 操场


Key differences主要区别

The key differences between the 3 approaches:三种方法之间的主要区别:

  • The default implementation makes the trait bounds inherent to the method's signature, so all types which impl Test must be sized, and have a FromStr impl with a debuggable error type.默认实现使特征边界成为方法签名所固有的,因此所有impl Test的类型都必须调整大小,并具有带有可调试错误类型的FromStr impl。
  • The default implementation allows you to selectively pick which types get Test implementations.默认实现允许您有选择地选择哪些类型获得Test实现。
  • The generic implementation doesn't add any trait bounds to the trait method's signature so a greater variety of types could potentially implement the trait.通用实现不会向 trait 方法的签名添加任何 trait 边界,因此更多种类的类型可能会实现该 trait。
  • The generic implementation automatically implements the trait for all types which satisfy the bounds, you cannot selectively "opt out" of the generic implementation if there are some types which you'd prefer not to implement the trait.泛型实现会自动为所有满足边界的类型实现特征,如果有某些类型您不想实现特征,则不能选择性地“退出”泛型实现。
  • The macro implementation does not require modifying the trait method signature with additional trait bounds and allows you to selectively pick which types get the implementation.宏实现不需要使用额外的特征边界修改特征方法签名,并允许您有选择地选择哪些类型得到实现。
  • The macro implementation is a macro and suffers all the downsides of being a macro: harder to read, write, maintain, increases compile times, and macros are essentially opaque to static code analyzers which makes it harder to easily type-check your code.宏实现是一个宏,并且具有作为宏的所有缺点:难以读取、写入、维护、增加编译时间,并且宏对 static 代码分析器基本上是不透明的,这使得更难轻松地对代码进行类型检查。

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

相关问题 C ++:如何对同一数据类使用不同的方法实现? - C++: How can I use different implementation of methods with the same data class? 如何在Rust中使用对象作为其自身方法的参数? - How can I use an object as a parameter of its own method in Rust? 如何在 Trait 中获取可调用方法? - How can I get the callable method in a Trait? 如何使用 Python 中的 class 变量作为方法的默认参数? - How can I use a class variable in Python as a default argument for a method? 有没有一种方法可以使用后缀表示法在Rust中调用函数而不定义新特性? - Is there a way to use postfix notation to call a function in Rust without defining a new trait? 如何使用“如果”做同样的工作? - How can I use one “if” to do the same job? 如何删除仅在类型上有所不同但使用非默认构造函数的方法之间的重复? - How can I remove duplication between methods that differ only on type but use non-default constructors? 我可以对不同的类使用相同的属性吗? - Can i use the same properties for different classes? 如何在 Rust 中使用方法作为 function 指针 - How to use a method as a function pointer in Rust 如何创建 Struct 方法并在 Rust 中使用它们 - How to create Struct methods and use them in Rust
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM