Почему я получаю ошибку размера при использовании псевдонима типа `dyn Trait`?

Эта функция компилирует:

fn edit<S: AsRef<str>>(w: S) {}

Если я наберу общие параметры:

type Word = dyn AsRef<str>;

fn edit(w: Word) {}

Я получаю сообщение об ошибке:

error[E0277]: the size for values of type `(dyn std::convert::AsRef<str> + 'static)` cannot be known at compilation time
 --> src/lib.rs:3:9
  |
3 | fn edit(w: Word) {}
  |         ^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `(dyn std::convert::AsRef<str> + 'static)`
  = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
  = note: all local variables must have a statically known size
  = help: unsized locals are gated as an unstable feature

Почему это происходит?


person nz_21    schedule 07.01.2020    source источник


Ответы (1)


Все функции должны знать размер своих аргументов во время компиляции. Однако вы используете w, размер которого не может быть определен во время компиляции. Вместо того, чтобы иметь возможность выполнять динамическую отправку, вам необходимо использовать объект-признак. Вы можете сделать это двумя способами.

Вы можете передать указатель, используя Box:

fn edit(w: Box<Word>)

или ссылка:

fn edit(w: &Word)

Другой вариант - вообще отказаться от использования признаков. Вместо этого вы можете сделать edit универсальным методом следующим образом:

fn edit(w: impl AsRef<str>)

or

fn edit<W: AsRef<str>>(w: W)

При таком подходе компилятор выполняет так называемую «мономорфизацию», когда он определяет во время компиляции, какие именно типы передаются для ваших общих аргументов, и генерирует несколько неуниверсальных версий для каждого из этих вызовов с этими конкретными типами. Мономорфизация довольно хорошо объясняется в Что такое мономорфизация в контексте C ++? .

person sshashank124    schedule 07.01.2020
comment
отличное объяснение, спасибо! Чтобы уточнить, в последнем фрагменте кода, как компилятор узнает размер w? Все, что он знает, это то, что он реализует AsRef<str> - person nz_21; 07.01.2020
comment
w, который является объектом признака - это не объект признака, который является проблемой. Что делает что-то «характерным объектом»? - person Shepmaster; 07.01.2020
comment
[мономорфизация] позволяет компилятору знать размер аргументов на каждом сайте вызова - не совсем так, как вы все еще можете передать безразмерный dyn Trait в качестве универсального аргумента - person Shepmaster; 07.01.2020
comment
Я сделал неверное предположение. Я удалил эту часть. Спасибо за все указатели - person sshashank124; 07.01.2020
comment
Хорошее объяснение. Тем не менее, стоит упомянуть, что вы можете отказаться от определения размеров общих параметров: fn edit<T: ?Sized>(t: &T). - person Markus Klein; 07.01.2020
comment
@MarkusKlein, в каком контексте вы имеете в виду? я не уверен, что следую - person sshashank124; 07.01.2020
comment
@ sshashank124 Теперь, когда я снова думаю об этом, я чувствую, что просто перепутал размер аргументов с размером общих параметров. Ваш ответ в порядке, извините. - person Markus Klein; 09.01.2020