2016-08-11 5 views
2

Der Versuch, &[u8] als Argument für eine Funktion, die Read erfordert scheint scheint nicht zu funktionieren, wie ich erwartet hatte, wie im folgenden Beispiel veranschaulicht.Casting & [u8] to std :: io :: Lesen verursacht Größe Problem

use std::io::Read; 

fn main() { 
    let bytes: &[u8] = &[1, 2, 3, 4]; 
    print_reader(&bytes); 
} 

fn print_reader(reader: &(Read + Sized)) { 
    for byte in reader.bytes() { 
     println!("{}", byte.unwrap()); 
    } 
} 

Compiler-Fehler:

error: the trait bound `std::io::Read + Sized: std::marker::Sized` is not satisfied [--explain E0277] 
--> <anon>:9:24 
9 |>  for byte in reader.bytes() { 
    |>      ^^^^^ 
note: `std::io::Read + Sized` does not have a constant size known at compile-time 

error: the trait bound `std::io::Read + Sized: std::marker::Sized` is not satisfied [--explain E0277] 
--> <anon>:9:5 
9 |>  for byte in reader.bytes() { 
    |> ^
note: `std::io::Read + Sized` does not have a constant size known at compile-time 
note: required because of the requirements on the impl of `std::iter::Iterator` for `std::io::Bytes<std::io::Read + Sized>` 

error: aborting due to 2 previous errors 

Rust playground

Die Implementierung folgende Eigenschaft kann in der std::slice Dokumentation:

impl<'a> Read for &'a [u8].

Antwort

2

I denken Dies ist eine eher nicht hilfreiche Fehlermeldung. Ich werde versuchen zu erklären:


Erste: Sie können nicht &Sized ein Merkmal Objekt haben. Dies verletzt die first object safety rule und es ergibt auch keinen Sinn. Der einzige Grund für das Hinzufügen der Sized-Eigenschaft ist die Verwendung der speziellen Eigenschaft aller Sized-Typen (z. B. Speichern auf dem Stapel). Schauen Sie sich dieses Beispiel versuchen, die Eigenschaft zu verwenden:

fn foo(x: &Sized) { 
    let y = *x; 
} 

Welche Größe würde y haben? Der Compiler kann nicht wie bei jedem anderen Merkmalsobjekt wissen. Daher können wir nicht den einzigen Zweck von Sized mit Merkmalobjekten verwenden. Somit ist ein Merkmalsobjekt &Sized nutzlos und kann nicht wirklich existieren.

In diesem Fall wird die Fehlermeldung mindestens Art sagt uns die richtige Sache:

error: the trait `std::marker::Sized` cannot be made into an object [--explain E0038] 
--> <anon>:7:1 
7 |> fn foo(x: &Sized) { 
    |>^
note: the trait cannot require that `Self : Sized` 

Außerdem: Ich vermute, Sie fügte der + Sized gebunden um den gleichen Fehler arbeiten, die bereits tauchte auf, als Sie das Argument reader: &Read hatten. Hier ist eine wichtige Erkenntnis aus der detaillierten Fehlerbeschreibung:

Generally, Self : Sized is used to indicate that the trait should not be used as a trait object.

Diese Einschränkung für Read::bytes nicht sinnvoll, da die Bytes Iterator Read::read() einmal für jedes einzelne Byte aufruft. Wenn dieser Funktionsaufruf ein virtueller/dynamischer Aufruf wäre, wäre der Aufwand für den Funktionsaufruf viel höher als der tatsächliche Prozess von read das Byte.


So ... warum brauchen Sie Read als Merkmal Objekt sowieso haben? Oft ist es ausreichend (und auf jeden Fall viel schneller) dies über Generika zu behandeln:

fn print_reader<R: Read>(reader: R) { 
    for byte in reader.bytes() { 
     println!("{}", byte.unwrap()); 
    } 
} 

Dies vermeidet dynamische Dispatch und arbeitet gut mit dem Typ-Checker und Optimierer.