Что означает «размер не реализовано»?

Я написал следующий код:

use std::io::{IoResult, Writer}; use std::io::stdio; fn main() { let h = |&: w: &mut Writer| -> IoResult { writeln!(w, "foo") }; let _ = h.handle(&mut stdio::stdout()); } trait Handler where W: Writer { fn handle(&self, &mut W) -> IoResult; } impl Handler for F where W: Writer, F: Fn(&mut W) -> IoResult { fn handle(&self, w: &mut W) -> IoResult { (*self)(w) } } 

А потом rustc в моем терминале:

 $ rustc writer_handler.rs writer_handler.rs:8:15: 8:43 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Writer` writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ writer_handler.rs:8:15: 8:43 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Writer` writer_handler.rs:8 let _ = h.handle(&mut stdio::stdout()); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

Почему этот Writer требуется для реализации Sized ? Мне кажется, что Sized не нужен. Что я должен делать, сохраняя при этом trait Handler этот общий аргумент?


В Rust 1.0 этот аналогичный код создает ту же проблему:

 use std::io::{self, Write}; fn main() { handle(&mut io::stdout()); } fn handle(w: &mut Write) -> io::Result { handler(w) } fn handler(w: &mut W) -> io::Result where W: Write, { writeln!(w, "foo") } 

С ошибкой:

 error[E0277]: the trait bound `std::io::Write: std::marker::Sized` is not satisfied --> src/main.rs:8:5 | 8 | handler(w) | ^^^^^^^ `std::io::Write` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::io::Write` = note: required by `handler` 

Sized признак является довольно особенным, поэтому он отличается тем, что в большинстве случаев он связан с параметрами типа по умолчанию. Он представляет значения, которые имеют фиксированный размер, известный во время компиляции, например u8 (1 байт) или &u32 (8 байтов на платформе с 64-разрядными указателями) и т. Д. Эти значения являются гибкими: их можно поместить в стек и переместить на куча и, как правило, передается по значению, поскольку компилятор знает, сколько места ему нужно, где бы оно ни было.

Типы, которые не имеют размера, гораздо более ограничены, а значение типа Writer не имеет размера: оно представляет абстрактно некоторый неопределенный тип, который реализует Writer , не зная, что такое фактический тип. Поскольку фактический тип неизвестен, размер не может быть известен: некоторые крупные типы – Writer s, некоторые небольшие типы. Writer – это один из примеров объекта-объекта, который на данный момент может отображаться только в исполняемом коде за указателем. Среди распространенных примеров: &Writer , &mut Writer или Box .

Это объясняет, почему значение Sized является стандартным: часто требуется то, что нужно.

В любом случае, для вашего кода это появляется, потому что вы используете handle с h , который является Fn(&mut Writer) -> IoResult<()> . Если мы сопоставим это с типом F: Fn(&mut W) -> IoResult<()> который Handle , мы обнаруживаем, что W = Writer , то есть мы пытаемся использовать handle с объектом trait &mut Writer , не a &mut W для некоторого конкретного типа W Это незаконно, потому что параметры W как в черте, так и в impl по умолчанию имеют размерную границу, если мы вручную переопределяем ее с ?Sized тогда все работает нормально:

 use std::io::{IoResult, Writer}; use std::io::stdio; fn main() { let h = |&: w: &mut Writer| -> IoResult<()> { writeln!(w, "foo") }; let _ = h.handle(&mut stdio::stdout()); } trait Handler where W: Writer { fn handle(&self, &mut W) -> IoResult<()>; } impl Handler for F where W: Writer, F: Fn(&mut W) -> IoResult<()> { fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) } } 

И для кода Rust 1.0:

 use std::io::{self, Write}; fn main() { handle(&mut io::stdout()); } fn handle(w: &mut Write) -> io::Result<()> { handler(w) } fn handler(w: &mut W) -> io::Result<()> where W: Write, { writeln!(w, "foo") } 

Я также написал сообщение в блоге об объектах Sized и trait в целом, которое имеет немного более подробную информацию.

Прежде всего, обратите внимание, что h имеет тип, который реализует Fn(&mut Writer) -> IoResult<()> .

h.handle вызывается; это зависит, следовательно, от реализации Handler где WWriter обратите внимание на то, что W – это Writer , нестандартный тип. Поэтому &mut stdio::stdout() будет передаваться в объект- &mut Writer . В теории все это очень хорошо, но при возврате к реализации падает. Когда дело доходит до ограничений, они имеют размер по умолчанию, и поэтому он жалуется, что Writer , значение, которое вы пытаетесь назначить для W , не имеет размера.

Здесь есть два основных решения:

  1. Переключитесь на конкретный тип записи на h чтобы иметь дело с типом размера:

     use std::io::{IoResult, Writer, stdio, LineBufferedWriter}; use std::io::stdio::StdWriter; fn main() { let h = |&: w: &mut LineBufferedWriter| -> IoResult<()> { writeln!(w, "foo") }; let _ = h.handle(&mut stdio::stdout()); } trait Handler where W: Writer { fn handle(&self, &mut W) -> IoResult<()>; } impl Handler for F where W: Writer, F: Fn(&mut W) -> IoResult<()> { fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) } } 
  2. Разрешить W быть нестандартным типом. Это приемлемо, поскольку вы используете его только через reference &mut W Если вы хотите использовать его как голый тип, например метод, принимающий W по значению, это не будет сделано.

     use std::io::{IoResult, Writer}; use std::io::stdio; fn main() { let h = |&: w: &mut Writer| -> IoResult<()> { writeln!(w, "foo") }; let _ = h.handle(&mut stdio::stdout()); } trait Handler where W: Writer { fn handle(&self, &mut W) -> IoResult<()>; } impl Handler for F where W: Writer, F: Fn(&mut W) -> IoResult<()> { fn handle(&self, w: &mut W) -> IoResult<()> { (*self)(w) } } 

Я бы рекомендовал поддерживать нестандартную W даже если вы тогда не используете это в этом случае – нет причин, по которым он должен быть рассчитан.

  • Не может заимствовать как неизменяемый, поскольку он также заимствован как изменяемый в аргументах функции
  • Возrotation замыкания из функции
  • Можно ли управлять размером массива с помощью параметра типа общего?
  • Автоматически реализовать черты замкнутого типа для новых типов Rust (кортежи с одним полем)
  • Почему мой пользователь не вводит корректное соответствие stdin?
  • Преобразовать строку в int в Rust?
  • Передача изменчивой самостоятельной ссылки на метод принадлежащего ему объекта
  • Вектор объектов, принадлежащих признаку
  • Могу ли я делать интроспекцию типа с объектами признаков, а затем опускать ее?
  • Внедрение признака для нескольких типов одновременно
  • Как проверить равенство между объектами признаков?
  • Давайте будем гением компьютера.