Rust關聯類型與默認泛型類型參數

一、關聯類型(associated types)

我們閱讀Rust程式的時候,有時候會出現如下的程式碼:

trait Iterator {
    type Item; 
    fn next(&mut self) -> Option<Self::Item>;
}

下面是上面程式碼的註解:Iterator trait 有一個關聯類型 ItemItem是一個佔位類型,同時 next 方法會返回 Option<Self::Item>類型的值。這個 trait的實現者會指定 Item的具體類型。

這裡的type用法就是關聯類型。

關聯類型(associated types)是一個將類型佔位符與 trait 相關聯的方式,這樣 trait 的方法簽名中就可以使用這些佔位符類型。trait 的實現者會針對特定的實現在這個類型的位置指定相應的具體類型。如此可以定義一個使用多種類型的 trait,直到實現此 trait 時都無需知道這些類型具體是什麼。

使用關聯類型的程式碼示例如下:

pub trait Watch {
    type Item;
    fn inner(&self) -> Option<Self::Item>;
}

struct A {
    data: i32,
}

impl Watch for A {
    type Item = i32;
    fn inner(&self) -> Option<Self::Item> {
        Some(self.data)
    }
}

struct B {
    data: String,
}

impl Watch for B {
    type Item = String;
    fn inner(&self) -> Option<Self::Item> {
        Some(self.data.clone())
    }
}

fn main() {
    let a = A{data: 10};
    let b = B{data: String::from("B")};
    assert_eq!(Some(10), a.inner());
    assert_eq!(Some(String::from("B")), b.inner());
}
二、默認泛型類型參數

我們還會碰到如下類型的程式碼:

#[lang = "add"]
pub trait Add<RHS = Self> {
    type Output;
    
    #[must_use]
    fn add(self, rhs: RHS) -> Self::Output;
}

這裡Add<RHS = Self>是默認泛型類型參數,表示如果不顯示指定泛型類型,就默認泛型類型為Self

當使用泛型類型參數時,可以為泛型指定一個默認的具體類型。如果默認類型就足夠的話,這消除了為具體類型實現 trait 的需要。為泛型類型指定默認類型的語法是在聲明泛型類型時使用 <PlaceholderType=ConcreteType>。

使用默認泛型類型參數的示例程式碼如下:

pub trait Watch<Inner=String> {
    type Item;
    fn inner(&self) -> Option<Self::Item>;
    fn info(&self) -> Inner;
}

struct A {
    data: i32,
}

impl Watch<i32> for A {
    type Item = i32;
    fn inner(&self) -> Option<Self::Item> {
        Some(self.data)
    }
    fn info(&self) -> i32 {
        println!("A inner is {}", self.data);
        self.data
    }
}

struct B {
    data: String,
}

impl Watch for B {
    type Item = String;
    fn inner(&self) -> Option<Self::Item> {
        Some(self.data.clone())
    }
    fn info(&self) -> String {
        println!("B inner is {}", self.data);
        self.data.clone()
    }
}

fn main() {
    let a = A{data: 10};
    let b = B{data: String::from("B")};
    assert_eq!(10, a.info());
    assert_eq!(Some(String::from("B")), b.inner());
}
Tags: