2016-06-03 8 views
7

Sono in procinto di implementare una classe Bit Vector come esercizio, tuttavia solo conoscendo Rust per meno di una settimana mi trovo nei guai con il seguente codice :Operazione binaria! = Non può essere applicata quando si usano i generici per un vettore bit

use std::cmp::Eq; 
use std::ops::BitAnd; 
use std::ops::Index; 
use std::ops::Not; 

struct BitVector<S = usize> 
    where S: Sized + BitAnd<usize> + Not + Eq { 
    data: Vec<S>, 
    capacity: usize 
} 

impl<S> BitVector<S> 
    where S: Sized + BitAnd<usize> + Not + Eq { 
    fn with_capacity(capacity: usize) -> BitVector { 
     let len = (capacity/(std::mem::size_of::<S>() * 8)) + 1; 
     BitVector { data: vec![0; len], capacity: capacity } 
    } 
} 

impl<S> Index<usize> for BitVector<S> 
    where S: Sized + BitAnd<usize> + Not + Eq { 
    type Output = bool; 

    fn index(&self, index: usize) -> &bool { 
     let data_index = index/(std::mem::size_of::<S>() * 8); 
     let remainder = index % (std::mem::size_of::<S>() * 8); 
     (self.data[data_index] & (1 << remainder)) != 0 
    } 
} 

L'idea è che S può essere uno per esempio u8, u16, u32, u64 e usize garantire che impostandola 0 in with_capacity crea un valore di bit per S che consiste di tutti zeri.

L'errore che ottengo è il seguente:

lib.rs:27:10: 27:50 error: binary operation != cannot be applied to type <S as std::ops::BitAnd<usize>>::Output [E0369]
lib.rs:27 (self.data[data_index] & (1 << remainder)) != 0
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lib.rs:27:10: 27:50 help: run rustc --explain E0369 to see a detailed explanation
lib.rs:27:10: 27:50 note: an implementation of std::cmp::PartialEq might be missing for <S as std::ops::BitAnd<usize>>::Output
lib.rs:27 (self.data[data_index] & (1 << remainder)) != 0 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
error: Could not compile bit-vector .

+2

Non voglio a piovere sulla tua parata, ma 'Indice :: index' restituisce un' & Output' quindi non si può calcolare al volo. .. –

risposta

5

Questo particolare errore qui, in termini semplici, significa che il Output di BitAnd ing S e usize non implementa PartialEq. Una soluzione potrebbe essere quella di aggiungere un vincolo che S s' BitAnd<usize> s Output è S:

BitAnd<usize, Output = S> 

Dopo questo, si incorrerà in un altro errore, perché si sta confrontando il valore della BitAnd per 0 e non a un valore di tipo S. Per risolvere il problema è possibile definire il proprio tratto Zero e utilizzarlo oppure utilizzare l'instabile di Rust std::num::Zero e confrontarlo con S::zero().

Dovrete anche a fare in modo che S: Copy facendo la BitAnd non consuma il valore (o aggiungere S: Clone ed esplicitamente clonare prima di chiamare BitAnd::bitand).

Infine si verificherà un errore che il tuo index deve restituire un &bool mentre si restituisce un bool. È possibile utilizzare il trucco bit-vec utilizza per definire 2 statica:

static TRUE: bool = true; 
static FALSE: bool = false; 

e ritorno &TRUE o &FALSE da index.

di lavoro finale (su Nightly) Codice:

#![feature(zero_one)] 

use std::cmp::Eq; 
use std::num::Zero; 
use std::ops::BitAnd; 
use std::ops::Index; 
use std::ops::Not; 

struct BitVector<S = usize> 
    where S: Sized + BitAnd<usize, Output = S> + Not + Eq + Copy + Zero 
{ 
    data: Vec<S>, 
    capacity: usize, 
} 

impl<S> BitVector<S> 
    where S: Sized + BitAnd<usize, Output = S> + Not + Eq + Copy + Zero 
{ 
    fn with_capacity(capacity: usize) -> BitVector { 
     let len = (capacity/(std::mem::size_of::<S>() * 8)) + 1; 
     BitVector { 
      data: vec![0; len], 
      capacity: capacity, 
     } 
    } 
} 

static TRUE: bool = true; 
static FALSE: bool = false; 

impl<S> Index<usize> for BitVector<S> 
    where S: Sized + BitAnd<usize, Output = S> + Not + Eq + Copy + Zero 
{ 
    type Output = bool; 

    fn index(&self, index: usize) -> &bool { 
     let data_index = index/(std::mem::size_of::<S>() * 8); 
     let remainder = index % (std::mem::size_of::<S>() * 8); 
     if (self.data[data_index] & (1 << remainder)) != S::zero() { 
      &TRUE 
     } else { 
      &FALSE 
     } 
    } 
} 

fn main() { 
} 
+0

Grazie mille! Questo non è stato immediatamente chiaro dagli errori del compilatore fino ad ora. L'intestazione "& TRUE & FALSE'" è intesa o una lacuna linguistica al momento? E infine c'è un modo idiomatico per evitare di copiare 'S: Sized + BitAnd + Not + Eq + Copy + Zero' dappertutto? – skiwi

+0

Credo che al momento sia una lacuna, ma non sono sicuro che cambierà in futuro. Ci sono [molte discussioni] (https://www.google.com/search?q=site%3Areddit.com%2Fr%2Frust+index+return+value) su questo sul subreddit di Rust, ad es. [questo] (https://www.reddit.com/r/rust/comments/2umad5/the_output_of_the_index_trait_should_be_a_value/) se vuoi leggere spiegazioni dettagliate. – Dogbert

+0

Sì, puoi usare l'ereditarietà dei tratti per quello. Vedi http://stackoverflow.com/questions/26983355/is-there-a-way-to-combine-multiple-traits-in-order-to-define-a-new-trait. Demo: https://play.rust-lang.org/?gist=efa13f778d31cdd6f90e79962fd379d2&version=nightly&backtrace=0 – Dogbert

Problemi correlati