2017-03-25 40 views
2

我有一個帶有兩個通用typenum參數的impl。當參數相同時,impl的函數應該返回一個不同的類型。 (不同的類型是一個更緊湊的表示,只能在類型參數相同時才能實現)。是否可以使用基於類型相等的不同impl?下面的天真方法會產生一個「衝突的實現」錯誤,因爲Rust沒有采用更具體的實現。當類型參數相同時使用不同的impl

extern crate typenum; 
use typenum::Unsigned; 

use std::ops::Mul; 
use std::marker::PhantomData; 

struct Matrix<N: Unsigned, M: Unsigned> { 
    n: usize, 
    m: usize, 
    elements: Vec<f64>, 
    _marker: PhantomData<(N, M)> 
} 

// The more compact representation 
struct SquareMatrix<N: Unsigned> { 
    n: usize, 
    elements: Vec<f64>, 
    _marker: PhantomData<(N)> 
} 

impl<N: Unsigned, D: Unsigned, M: Unsigned> Mul<Matrix<D, M>> for Matrix<N, D> { 
    type Output = Matrix<N, M>; 
    fn mul(self, rhs: Matrix<D, M>) -> Self::Output { 
     unimplemented!() 
    } 
} 

// The more specific implementation 
impl<N: Unsigned, D: Unsigned> Mul<Matrix<D, N>> for Matrix<N, D> { 
    type Output = SquareMatrix<N>; 
    fn mul(self, rhs: Matrix<D, N>) -> Self::Output { 
     unimplemented!() 
    } 
} 

回答

2

隨着specialization(這仍然是不穩定的防鏽1.16.0的),就可以了。基本上,您需要的只是在default的更一般的實現中聲明這些項目,以表示「這可以是專用的」。

#![feature(specialization)] 

impl<N: Unsigned, D: Unsigned, M: Unsigned> Mul<Matrix<D, M>> for Matrix<N, D> { 
    default type Output = Matrix<N, M>; 

    default fn mul(self, rhs: Matrix<D, M>) -> Self::Output { 
     unimplemented!() 
    } 
} 

// The more specific implementation 
impl<N: Unsigned, D: Unsigned> Mul<Matrix<D, N>> for Matrix<N, D> { 
    type Output = SquareMatrix<N>; 

    fn mul(self, rhs: Matrix<D, N>) -> Self::Output { 
     unimplemented!() 
    } 
} 
+0

在Rust特徵門後面找不到好東西。 – drhagen

+0

我在哪裏可以找到「專業化」的文檔?它沒有列出[這裏](https://doc.rust-lang.org/nightly/reference/attributes.html#compiler-features)或[here](https://doc.rust-lang.org/reference。 HTML#編譯器的功能);是否有其他地方我應該查看可用/可能的'功能'列表? – ildjarn

+1

目前關於專業化的最佳文檔可能是我鏈接到的RFC。缺乏新功能的文檔是[已知問題](https://github.com/rust-lang/rfcs/blob/master/text/1636-document_all_features.md)。可用編譯器功能的詳盡列表可能只存在於編譯器的源代碼中。 –

2

你現在可以在穩定的Rust中做到這一點,它只需要一些額外的鍋爐板。

首先,我們將創建一個內部繁殖性狀,會做實際的工作:

pub trait MulPrivate<Rhs, AreEqual> { 
    type Output; 
    fn mul_private(self, rhs: Rhs) -> Self::Output; 
} 

注意額外的類型參數:這就是我們將如何區分這兩種情況。

然後,我們做我們的常規Mul實現調出這個內部之一:

use typenum::{IsEqual, Eq}; 
impl<N, M, D> Mul<Matrix<D, M>> for Matrix<N, D> 
    where D: Unsigned, 
      M: Unsigned, 
      N: Unsigned + IsEqual<M>, 
      Matrix<N, D>: MulPrivate<Matrix<D, M>, Eq<N, M>>, 
{ 
    type Output = <Matrix<N, D> as MulPrivate<Matrix<D, M>, Eq<N, M>>>::Output; 
    fn mul(self, rhs: Matrix<D, M>) -> Self::Output { 
     self.mul_private(rhs) 
    } 
} 

這使我們能夠比較NM。如果它們相等,那麼額外的類型參數將是True,否則將是False。現在,我們可以自由地做出的MulPrivate兩個不同的實現:

use typenum::{True, False}; 
impl<N: Unsigned, D: Unsigned, M: Unsigned> MulPrivate<Matrix<D, M>, False> for Matrix<N, D> { 
    type Output = Matrix<N, M>; 
    fn mul_private(self, rhs: Matrix<D, M>) -> Self::Output { 
     println!("not square!"); 
     unimplemented!() 
    } 
} 

// The more specific implementation 
impl<N: Unsigned, D: Unsigned> MulPrivate<Matrix<D, N>, True> for Matrix<N, D> { 
    type Output = SquareMatrix<N>; 
    fn mul_private(self, rhs: Matrix<D, N>) -> Self::Output { 
     println!("square!"); 
     unimplemented!() 
    } 
} 

注意,一旦this issue解決了,你就可以擺脫這一切的樣板,並可以寫爲:

impl<N: Unsigned, D: Unsigned, M: Unsigned> Mul<Matrix<D, M>> for Matrix<N, D> where N: IsEqual<M, Output = False> { 
    type Output = Matrix<N, M>; 
    fn mul(self, rhs: Matrix<D, M>) -> Self::Output { 
     unimplemented!() 
    } 
} 

// The more specific implementation 
impl<N: Unsigned, D: Unsigned> Mul<Matrix<D, N>> for Matrix<N, D> where N: IsEqual<N, Output = True> { 
    type Output = SquareMatrix<N>; 
    fn mul(self, rhs: Matrix<D, N>) -> Self::Output { 
     unimplemented!() 
    } 
} 
相關問題