2016-08-11 3 views
2

Попытка предоставить &[u8] в качестве аргумента функции, требующей Read, кажется, не работает, как я ожидал, как показано в приведенном ниже примере.Кастинг и [u8] в std :: io :: Чтение причин Sized issue

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 ошибка:

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

Следующая реализация черта можно найти в документации std::slice:

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

ответ

2

I думаю это довольно бесполезное сообщение об ошибке. Попробую объяснить:


Первый: вы не можете иметь объект признака &Sized. Это нарушает first object safety rule, и это тоже не имеет смысла. Единственная причина для добавления привязки атрибута Sized заключается в использовании специального свойства всех типов Sized (например, сохранение его в стеке). Посмотрите на этот пример пытается использовать свойство:

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

Какой размер будет y иметь? Компилятор не может знать, как и для любого другого объекта-объекта. Таким образом, мы не можем использовать единственную цель Sized с объектами признаков. Таким образом, объект объекта &Sized бесполезен и не может существовать.

В этом случае сообщение об ошибке, по крайней мере отчасти говорит нам правильные вещи:

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` 

Кроме: Я подозреваю, вы добавили + Sized обязаны работать вокруг одной и той же ошибки, которые уже появился, когда у вас был аргумент reader: &Read. Вот один важная проницательность из подробного описания ошибки:

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

Это ограничение для Read::bytes имеет смысл, потому что Bytes итератор вызывает Read::read() один раз для каждого байта. Если этот вызов функции будет виртуальным/динамическим, накладные расходы для вызова функции будут намного выше, чем фактический процесс read байта.


Итак ... почему вам нужно иметь Read как объект черта так или иначе? Часто это достаточно (и в любом случае гораздо быстрее) справиться с этим с помощью дженериков:

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

Это позволяет избежать динамической диспетчеризации и хорошо работает с типом проверки и оптимизатора.

 Смежные вопросы

  • Нет связанных вопросов^_^