Корка ржавчины: диспетчерские и жирные указатели

Обещал написать о том, что прочитал, выяснилось, для некоторых нужны видео и аудио.

Последнее, что меня впечатлило, - это видео от «Crust of Rust» об объектах-признаках в Rust (и в целом dyn).

Связь

Корка ржавчины: диспетчерские и жирные указатели от Jon Gjengset.

Medium очень хочет превратить эту ссылку во встроенную форму, поэтому повторяю:

https://www.youtube.com/watch?v=xcygqF5LVmM

Почему это хорошо

В своем путешествии по Rust я вроде бы знал, что они есть, но никогда не фокусировался на них, более того, я никогда не использовал их (что является признаком того, что я их не знал).

В этом коротком видео (извините, любители 10-минутного видео, но 2 часа - это действительно короткое видео для такой огромной темы) было основополагающим объяснением свойств dyn. Вместо магического мышления книги Rust был по-настоящему инженерный подход к объяснению ограничений и причин.

Он заложил отличную основу благодаря стилю «не бояться идти на поводу». Мы не можем использовать объекты без размера, потому что нам нужно знать, сколько байтов занимает аргумент функции. Бум. Здесь нет магии.

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

Что я узнал

dyn ключевое слово в Rust используется для создания (или требует создания) объекта особого типа, называемого «Trait Object». Сам по себе это кортеж из двух указателей - на данные (значения структуры, которые использовались для создания этого объекта) и на vtable - таблицу вызовов всех функций, связанных с признаком. Когда какой-либо объект (реализующий конкретную характеристику) обращается к объекту характеристики, сохраняется только информация о релевантных (специфичных для характеристики) вызовах. Вызовы указывают на конкретную (конкретную) реализацию, которая идеально соответствует данным под указателем данных.

Типажи Dyn позволяют динамическую типизацию в Rust. Они внедряют «утиную типизацию» (если это Div, мы можем разделить его, и мы понятия не имеем, что это означает для определенного типа. Возможно, какое-то разделение).

Более того, они действительно хорошо скрывают дженерики от пользователей структур. Если мы хотим сохранить указатель функции в структуре, есть два варианта: сохранить указатель на объект dyn или сделать эту структуру универсальной.

Я получил подтверждение своего интуитивного описания типа str (как нечто, на что вы можете указать, но ничего не можете с этим поделать), но в точных терминах без размера.

(Конечно, за эти два часа намного больше, сомневаюсь, что смогу все это повторить).

Непредвиденный

Я обнаружил одну неожиданную вещь: использование &dyn Fn() может серьезно уменьшить размер кода. Если есть много универсальных типов, они мономорфизируются, и если эта функция велика, и есть много вариантов типов для мономорфизации, dyn может быть хорошим решением.

Во-вторых: существование std :: any, интересного инструмента для самоанализа (который, как мне кажется, отсутствует в Rust).

Третий: что Rust допускает структуры неопределенного размера:

struct Foo{
  foo: bool,
  bar: [u8]
}

Это не ящик в куче, это конструкция, у которой нет размера. Веселый.