2016-06-10 37 views
5

Próbuję zaimplementować bibliotekę wektorów bitowych jako ćwiczenie, jednak napotykam problemy, gdy chcę zdefiniować domyślną wartość ogólnego parametru typu.Domyślny parametr typu ogólnego nie może być wywnioskowany

Jest to fragment kodu mam:

extern crate num; 

use std::cmp::Eq; 
use std::ops::{BitAnd,BitOrAssign,Index,Shl}; 
use num::{One,Zero,Unsigned,NumCast}; 

pub trait BitStorage: Sized + 
    BitAnd<Self, Output = Self> + 
    BitOrAssign<Self> + 
    Shl<Self, Output = Self> + 
    Eq + Zero + One + Unsigned + NumCast + Copy {} 

impl<S> BitStorage for S where S: Sized + 
    BitAnd<S, Output = S> + 
    BitOrAssign<S> + 
    Shl<S, Output = S> + 
    Eq + Zero + One + Unsigned + NumCast + Copy {} 

pub struct BitVector<S: BitStorage = usize> { 
    data: Vec<S>, 
    capacity: usize 
} 

impl<S: BitStorage> BitVector<S> { 
    pub fn with_capacity(capacity: usize) -> BitVector<S> { 
     let len = (capacity/(std::mem::size_of::<S>() * 8)) + 1; 
     BitVector { data: vec![S::zero(); len], capacity: capacity } 
    } 

    //... 
} 

I chcę go używać w następujący sposób:

let vec = BitVector::with_capacity(1024); 

Jednakże pojawia się błąd kompilatora:

lib.rs:225:24: 225:48 error: unable to infer enough type information about _ ; type annotations or generic parameter binding required [E0282]
lib.rs:225 let vec_1000 = BitVector::with_capacity(1000);
^~~~~~~~~~~~~~~~~~~~~~~~
lib.rs:225:24: 225:48 help: run rustc --explain E0282 to see a detailed explanation

Aby dodać trochę kontekstu do kodu, obecnie ważne typy dla BitStorage obejmują (ale nie są ograniczone do *)) u8, u16, u32, u64 i usize.

(*) Myślę, że można napisać niestandardową implementację u128 (tak jak przykład), jeśli zaimplementujesz wszystkie cechy tego typu.

Po wprowadzeniu google na temat problemu znalazłem RFC 213, który nie wydaje się być be stable yet. Jednak z drugiej strony HashMap obecnie na stabilnym używa wartości domyślnych, więc powinno działać, prawda?

Odpowiedz

3

Obsługa domyślnych parametrów typów jest nadal ograniczona, ale może być używana w niektórych przypadkach. Kiedy struct z parametru domyślnego typu jest używany do określenia typu zmiennej, parametr domyślny typ jest używany do określenia typu zmiennej:

// the type of vec is BitVector<usize>, so the type of 
// BitVector::with_capacity(1024) is correctly inferred 
let vec: BitVector = BitVector::with_capacity(1024); 

However on the other hand HashMap currently on stable is using default values, so it should be working, right?

Patrząc na kod HashMap źródłowego, możemy zobacz, że metody new i with_capacity są zaimplementowane z RandomState dla parametru i nie zależą od domyślnego parametru typu w HashMap. Wszystkie inne metody są implementowane jako ogólne na S, w tym inne metody "konstruktorskie", takie jak with_hasher.

Możesz napisać coś podobnego:

impl BitVector<usize> { 
    pub fn default_with_capacity(capacity: usize) -> BitVector<usize> { 
     // type is inferred 
     Self::with_capacity(capacity) 
    } 
} 

impl<S: BitStorage> BitVector<S> { 
    pub fn with_capacity(capacity: usize) -> BitVector<S> { 
     let len = (capacity/(std::mem::size_of::<S>() * 8)) + 1; 
     BitVector { 
      data: vec![S::zero(); len], 
      capacity: capacity, 
     } 
    } 

    // ... 
} 

// create with "default" BitStore 
let vec = BitVector::default_with_capacity(1024); 
// specify BitStore 
let vec = BitVector::<u32>::with_capacity(1024);