2016-06-10 29 views
5

Sto provando a implementare una libreria Bit Vector come esercizio, tuttavia sto riscontrando problemi quando si desidera definire un valore predefinito per un parametro di tipo generico.Il parametro di tipo generico predefinito non può essere dedotto

Questo è un estratto del codice che ho:

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 } 
    } 

    //... 
} 

E voglio usarlo come segue:

let vec = BitVector::with_capacity(1024); 

Tuttavia ottengo un errore di compilazione:

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

Per dare un po 'più di contesto al codice, i tipi attualmente validi per BitStorage includono (ma non sono limitati a *) u8, u16, u32, u64 e usize.

(*) Penso che si possa scrivere un'implementazione personalizzata u128 (come l'esempio) se si implementano tutti i tratti di quel tipo.

Dopo aver cercato su Google il problema, ho trovato RFC 213 che non sembra essere be stable yet. Tuttavia, d'altra parte HashMap attualmente su stabile utilizza valori predefiniti, quindi dovrebbe funzionare, giusto?

risposta

3

Il supporto per i parametri di tipo predefinito è ancora limitato, ma può essere utilizzato in alcuni casi. Quando un struct con il parametro tipo di default viene utilizzato per specificare il tipo di una variabile, il parametro tipo di default viene utilizzato per definire il tipo di variabile:

// 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?

Guardando il codice HashMap fonte, possiamo si osservi che i metodi new e with_capacity sono implementati con RandomState per il parametro S e non dipendono dal parametro di tipo predefinito in HashMap. Tutti gli altri metodi sono implementati come generici su S, inclusi altri metodi di "costruzione" come with_hasher.

È possibile scrivere qualcosa di simile:

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);