簡體   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