關(guān)聯(lián)類型

2018-08-12 22:03 更新

關(guān)聯(lián)類型

關(guān)聯(lián)類型是 Rust 的類型系統(tǒng)一個強(qiáng)大的部分。它們與一個“類型家族”的概念有關(guān),換句話說,就是將多種類型組合在一起。這樣描述有點(diǎn)抽象,所以讓我們深入理解一個例子。如果你想寫一個特征,名字為 Graph ,你有2種類型是通用的:節(jié)點(diǎn)類型和邊類型。所以你可以寫一個特征 ,Graph<N, E>,看起來像這樣:

trait Graph<N, E> {
fn has_edge(&self, &N, &N) -> bool;
fn edges(&self, &N) -> Vec<E>;
// etc
}

但是這類代碼結(jié)束的不太合適。例如,任何想要以 Graph 為參數(shù)的函數(shù),現(xiàn)在也需要在節(jié)點(diǎn)和邊類型上是通用的:

fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }

我們的距離計(jì)算與我們的類型 Edge 無關(guān),所以填充在聲明中的 E 只是一個無關(guān)變量。

我們真正想說的是,邊 Edge 和 Node 類型一起構(gòu)成 Graph 類。我們可以稱它們?yōu)殛P(guān)聯(lián)類型:

trait Graph {
type N;
type E;

fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
// etc
}

現(xiàn)在,我們的客戶端可以抽象出一個給定的 Graph:

fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... }

這里不需要處理 Edge 類型!

讓我們更詳細(xì)地去學(xué)習(xí)這些知識。

定義關(guān)聯(lián)類型

讓我們構(gòu)建特征 Graph。這里是它的定義:

trait Graph {
type N;
type E;

fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
}

這很簡單。關(guān)聯(lián)類型要在特征函數(shù)體內(nèi)使用 type 關(guān)鍵字。    

這些 type 聲明可以有和函數(shù)一樣的功能。例如,如果我們希望我們的 N 類型實(shí)現(xiàn) Display,所以我們可以打印節(jié)點(diǎn),我們可以這樣做:

use std::fmt;

trait Graph {
type N: fmt::Display;
type E;

fn has_edge(&self, &Self::N, &Self::N) -> bool;
fn edges(&self, &Self::N) -> Vec<Self::E>;
}

關(guān)聯(lián)類型的實(shí)現(xiàn)

就像任何特征,使用關(guān)聯(lián)類型的特征要使用 impl 關(guān)鍵字提供實(shí)現(xiàn)。這是一個Graph 的簡單實(shí)現(xiàn):

struct Node;

struct Edge;

struct MyGraph;

impl Graph for MyGraph {
type N = Node;
type E = Edge;

fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
true
}

fn edges(&self, n: &Node) -> Vec<Edge> {
Vec::new()
}
}

這個簡單的實(shí)現(xiàn)總是返回 true 和一個空的 Vec <Edge>,但它給了你一個如何實(shí)現(xiàn)這種功能的辦法。我們首先需要三個struct,一個圖,一個節(jié)點(diǎn),一個邊。如果使用不同的類型,那也行,我們只是要用所有這三個變量的 struct?!   ?/p>

接下來是 impl,它就像實(shí)現(xiàn)任何其他特征一樣。    

在這里,我們使用 = 定義我們的關(guān)聯(lián)類型。特征使用的名字放在 = 的左側(cè),我們實(shí)現(xiàn)的具體類型放在 = 右邊。最后,我們使用函數(shù)中聲明的具體類型。

關(guān)聯(lián)類型的特征對象

還有一個語法我們應(yīng)該談?wù)撘幌拢禾卣鲗ο?。如果你想?chuàng)建一個關(guān)聯(lián)類型的特征對象,如下:

let graph = MyGraph;
let obj = Box::new(graph) as Box<Graph>;

你會得到兩個錯誤:

error: the value of the associated type `E` (from the trait `main::Graph`) must
be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;

24:44 error: the value of the associated type `N` (from the trait
`main::Graph`) must be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;

我們不能像這樣創(chuàng)建一個特征對象,因?yàn)槲覀儾恢狸P(guān)聯(lián)類型。相反,我們可以寫:

let graph = MyGraph;
let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;

N=Node 語法允許我們?yōu)?N 類型參數(shù)提供一個具體的類型,Node。E=Edge 也一樣。如果我們沒有提供這個約束,我們無法確定哪一個 impl 與這個特征對象相匹配。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號