2016-06-03 23 views
7

Ich bin dabei, eine Bit Vector-Klasse als Übung zu implementieren, jedoch kenne ich Rust erst seit weniger als einer Woche :Binäre Operation! = Kann nicht angewendet werden, wenn Generics für einen Bitvektor verwendet werden

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

Die Idee ist, dass S ein von zum Beispiel sein kann u8, u16, u32, u64 und usize um sicherzustellen, dass es zu 0 in with_capacity erzeugt einen Bit-Wert für S Einstellung, die nur aus Nullen besteht.

Der Fehler ich erhalte, ist die folgende:

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

Ich möchte nicht auf Ihre Parade regnen, aber 'Index :: index' eine' & Output' zurück, so dass Sie es nicht on the fly berechnen kann. .. –

Antwort

5

Dieser spezielle Fehler hier, in einfachen Worten bedeutet dies, dass die Output von BitAndS ing und usize nicht PartialEq nicht implementiert. Ein Update wäre eine Einschränkung hinzuzufügen, die S ‚s BitAnd<usize> s Output ist S:

BitAnd<usize, Output = S> 

Danach, werden Sie in einer anderen Fehler ausgeführt werden, da Sie den Wert des BitAnd zu 0 sind zu vergleichen und nicht zu ein Wert vom Typ S. Um das zu beheben, können Sie Ihre eigene Zero Eigenschaft definieren und diese verwenden oder Rust's unstableverwenden und mit S::zero() vergleichen.

Du musst auch S: Copy machen, so dass die BitAnd tun (klonen oder fügen Sie S: Clone und ausdrücklich vor BitAnd::bitand Aufruf) die den Wert nicht verbrauchen.

Schließlich wird ein Fehler auftreten, dass Ihre index eine &bool zurückgeben muss, während Sie eine bool zurückgeben. Sie können den Trick bit-vec 2 Statik zu definieren, verwendet:

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

und zurück &TRUE oder &FALSE von index.

Schlussbearbeitung (auf Nightly) Code:

#![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

Vielen Dank! Dies war bis jetzt nicht sofort aus den Compilerfehlern ersichtlich. Ist der "& TRUE & FALSE'" Hack "beabsichtigt" oder ein Sprachmangel im Moment? Und schließlich gibt es einen idiomatischen Weg, das Kopieren von "S: Sized + BitAnd + Not + Eq + Copy + Zero" überall zu vermeiden? – skiwi

+0

Ich glaube, es ist momentan ein Manko, aber ich bin mir nicht sicher, ob sich das in Zukunft ändern wird. Es gibt [viele Diskussionen] (https://www.google.com/search?q=site%3Areddit.com%2Fr%2Frust+index+return+value) darüber auf der Rust Subreddit, z. [this] (https://www.reddit.com/r/rust/comments/2umad5/the_output_of_the_index_trait_should_be_a_value/), wenn Sie detaillierte Erklärungen lesen möchten. – Dogbert

+0

Ja, Sie können dafür die Merkmalvererbung verwenden. Siehe 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