Потому что система дженериков Rust работает через мономорфизацию.
В Java, например, параметры типа в универсальной функции превращаются в переменные типа Object и приводятся по мере необходимости. Обобщения в таких языках, как этот, просто служат инструментом, помогающим проверить правильность типов в коде.
Такие языки, как Rust и C ++, используют мономорфизацию для дженериков. Для каждой комбинации параметров типа вызывается универсальная функция, генерируется специализированный машинный код, который запускает эту функцию с этими комбинациями параметров типа. Функция мономорфизируется. Это позволяет хранить данные на месте, исключает затраты на приведение типов и позволяет универсальному коду вызывать «статические» функции для этого параметра типа.
Так почему вы не можете сделать это для объекта-признака?
Объекты трейтов на многих языках, включая Rust, реализованы с помощью vtable. Когда у вас есть какой-либо тип указателя на объект-признак (необработанный, ссылка, бокс, счетчик ссылок и т. Д.), Он содержит два указателя: указатель на данные и указатель на запись vtable . Запись vtable - это набор указателей на функции, хранящихся в неизменяемой области памяти, которые указывают на реализацию методов этой черты. Таким образом, когда вы вызываете метод для объекта-признака, он ищет указатель функции реализации в vtable, а затем выполняет косвенный переход к этому указателю.
К сожалению, компилятор Rust не может мономорфизировать функции, если он не знает во время компиляции код, реализующий функцию, что имеет место, когда вы вызываете метод для объекта-признака. По этой причине вы не можете вызывать универсальную функцию (ну, универсальную функцию над типами) для объекта-признака.
-Редактировать-
Похоже, вы спрашиваете, зачем : Sized
ограничение.
: Sized
делает так, что признак не может использоваться как объект признака. Полагаю, может быть пара альтернатив. Rust может неявно сделать любую черту с универсальными функциями небезопасной для объектов. Rust также может неявно предотвращать вызов универсальных функций для объектов-признаков.
Однако Rust пытается явно указать, что делает компилятор, что противоречит этим неявным подходам. В любом случае, не было бы запутанным для новичка попытаться вызвать универсальную функцию для объекта-признака, и она не скомпилировалась?
Вместо этого Rust позволяет явно сделать весь трейт небезопасным для объекта.
trait Foo: Sized {
Или явно сделать определенные функции доступными только при статической отправке
fn foo<T>() where Self: Sized {
person
Phoenix
schedule
14.08.2018