Я хочу сослаться на конкретную структуру в файле Box<dyn Trait>
. Я точно знаю, что это за структура, поэтому могу использовать операции unsafe
. Когда я привожу его с использованием необработанных указателей, он дает SIGSEGV.
trait Help {}
struct Me {
data: Vec<String>
}
impl Help for Me {}
fn main() {
let me = Me { data: vec!["please".to_string(), "help".to_string()] };
let me: Box<dyn Help> = Box::new(me);
let inner = unsafe {
*(me.as_ref() as *const dyn Help as *const &Me)
};
dbg!(&inner.data);
assert_eq!(inner.data, vec!["hello", "world"]);
}
Я стараюсь избегать Any
, потому что в производственной логике его нет, и я хочу заглянуть во внутреннее состояние для тестов.
let inner = unsafe { &*(me.as_ref() as *const dyn Help as *const Me) };
но вам не следует этого делать, поскольку это зависит от точного расположения жирного указателя (&dyn Help
), о котором мы не должны знать.
@prog-fh Единственная проблема — лишний &
в &Me
(но as_ref()
также довольно небезопасен, и его лучше заменить на &*
).
Если вы не хотите использовать Any, просто скопируйте и вставьте код из реализации Any, заменив Any
на Help
, это всего пара строк (здесь)
@ChayimFriedman спасибо за решение, оно работает! Пожалуйста, опубликуйте это как ответ: D Я тестирую доказательство концепции, фактическая реализация не будет заглядывать во внутреннее состояние, поэтому Any
не нужен. Я заглядываю во внутреннее состояние только для проверки. Я добавлю этот контекст к вопросу. кстати Any
использует что-то похожее внутри.
Ну, если это только для проверки, это двойная причина не использовать unsafe, а использовать Any
.
Я считаю, что вникать в детали в тестах нехорошо, но даже если вы не согласны, все равно лучше добавить trait AsAny { #[cfg(test)] fn as_any(&self) -> &dyn Any }
и иметь это как суперпризнак.
Как я уже сказал в комментариях, я считаю, что не делать этого с небезопасным кодом — хорошая идея, но если вы действительно хотите, ваша ошибка будет лишней &
:
let inner = unsafe { &*(&*me as *const dyn Help as *const Me) };
Я также удалил as_ref()
, потому что это рискованно, вывод может привести к тому, что вы не планировали, и добавил &
вначале, потому что это было необходимо.
Если вы хотите стать владельцем структуры внутри, вы можете сначала получить необработанный указатель, используя into_raw
, а затем получить структуру, разыменовав новый блок, созданный с помощью необработанного указателя. Спасибо @kmdreko за указание на утечку памяти в моем предыдущем коде.
fn main() {
let me = Me { data: vec!["please".to_string(), "help".to_string()] };
let me: Box<dyn Help> = Box::new(me);
let p = Box::into_raw(me) as *mut Me;
let inner = unsafe {
*Box::from_raw(p)
};
dbg!(&inner.data);
assert_eq!(inner.data, vec!["hello", "world"]);
}
Я не думаю, что оно протекает. Для коробки ничего не выделено. Это просто указатель на что-то другое. Если вы посмотрите исходный код Drop for Box
, то увидите, что он ничего не делает, кроме освобождения указателя внутри. Да, согласен со вторым комментарием.
Что такое Мири? Возможно я ошибаюсь и мне стоит посмотреть. Но я думаю, что указатель — это вектор, и он освобождается, когда inner
выходит за пределы области видимости.
Извините, я ошибаюсь. Я отредактирую свой ответ, чтобы отразить это.
Почему ты пытаешься избегать
Any
? Это правильный путь.