Ответ 1
Прежде всего, у Руста нет рефлексии; отражение подразумевает, что вы можете получить информацию о типе во время выполнения, например, о полях, методах, интерфейсах, которые он реализует, и т.д. Вы не можете сделать это с помощью Rust. Самое близкое, что вы можете получить, явно реализует (или выводит) признак, предоставляющий эту информацию.
Каждый тип получает TypeId
, назначенный ему во время компиляции. Поскольку наличие глобально упорядоченных идентификаторов является сложным, идентификатор представляет собой целое число, полученное из комбинации определения типа и различных метаданных о ящике, в котором он содержится. Другими словами: они не назначены в каком-либо порядке, они просто хэши различных бит информации, которые входят в определение типа. [1]
Если вы посмотрите на источник для характеристики Any
, вы увидите единственную реализацию для Any
:
impl<T: Reflect + 'static + ?Sized> Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
(Оценки могут быть неофициально сведены к "всем типам, которые не заимствованы из чего-то другого".)
Вы также можете найти определение TypeId
:
pub struct TypeId {
t: u64,
}
impl TypeId {
pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
}
intrinsics::type_id
- это внутренняя функция, распознаваемая компилятором, которая при задании типа возвращает свой внутренний идентификатор типа. Этот вызов просто заменяется во время компиляции с литеральным идентификатором типа целого; здесь нет реального звонка. [2] Как TypeId
знает, что такое идентификатор типа. TypeId
, то это всего лишь обертка вокруг этого u64
, чтобы скрыть детали реализации от пользователей. Если вы считаете это концептуально более простым, вы можете просто подумать о типе TypeId
как о постоянном 64-битном целочисленном значении, которое компилятор просто знает во время компиляции.
Any
пересылает это значение из get_type_id
, что означает, что get_type_id
действительно просто привязывает метод признака к соответствующему методу TypeId::of
. Это просто, чтобы убедиться, что если у вас есть Any
, вы можете узнать исходный тип TypeId
.
Теперь для большинства типов реализовано Any
, но это не означает, что на всех этих типах фактически реализована реализация Any
в памяти. Фактически происходит то, что компилятор генерирует только фактический код для реализации типа Any
, если кто-то пишет код, который его требует. [3] Другими словами, если вы никогда не используете реализацию Any
для данного типа, компилятор никогда не будет генерировать его.
Вот как Rust выполняет "не плати за то, что вы не используете": если вы никогда не передаете данный тип как &Any
или Box<Any>
, тогда связанный код никогда не генерируется и никогда не занимает какое-либо место в ваш скомпилированный двоичный файл.
[1]: Разочарование означает, что тип TypeId
может изменять значение в зависимости от того, как библиотека скомпилирована, до такой степени, что компиляция в качестве зависимости (в отличие от автономной сборки) вызывает TypeId
для изменения.
[2]: Насколько я знаю. Я мог ошибаться в этом, но я был бы очень удивлен, если бы это произошло.
[3]: Обычно это относится к дженерикам в Rust.