2016-04-05 5 views
27

Rust имеет свойство Any, но также имеет политику «не платите за то, что вы не используете». Как Rust осуществляет отражение?Как отражается ржавчина?

Я предполагаю, что Rust использует ленивые метки. Каждый тип первоначально не назначен, но позже, если экземпляр типа передается функции, ожидающей признака Any, типу присваивается TypeId.

Или, может быть, Rust помещает TypeId на все типы, которые его экземпляр, возможно, передан этой функции? Наверное, первый был бы дорогим.

ответ

37

Прежде всего, Rust не имеет отражения; размышление подразумевает, что вы можете получить подробную информацию о типе во время выполнения, например, о полях, методах и интерфейсах, которые он реализует, и т. д. Вы не можете сделать это с помощью ржавчины. Самое близкое, что вы можете получить, явно реализует (или выводит) признак, который предоставляет эту информацию.

Каждый тип получает присвоенный ему TypeId во время компиляции. Поскольку глобально упорядоченные идентификаторы hard, идентификатор представляет собой целое число, полученное из комбинации определения типа и различных метаданных о ящике, в котором он содержится. Другими словами: они не назначены в каком-либо порядке, они всего лишь хешей различных бит информации, которые входят в определение типа. [1]

Если вы посмотрите на source for the Any trait, вы увидите единственную реализацию для 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 s для изменения.

[2]: Насколько я знаю. I может быть неправ об этом, но я был бы действительно удивлен, если это так.

[3]: Это обычно истинно дженериков в ржавчине.

+1

Интересно, что [документация для std :: any] (https://doc.rust-lang.org/std/any/) использует фразу «отражение во время выполнения», хотя кажется вероятным, что то, что они ссылаются не означает, что большинство из нас означает «отражение во время выполнения», поскольку это позволяет только проверять тип и тип каста, а не проверять содержимое произвольной структуры. – Ixrec

+0

OK. Под рефлексией я имею в виду RTTI. –

+0

Вы можете использовать 'TypeId' без' Any' для ограниченных форм ad-hoc для каждого типа специального корпуса без затрат времени исполнения. – bluss

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