Оба интеллектуальных указателя Rc<T>
и Box<T>
действительно имеют размер , они реализуют Sized
. Эта информация не представлена в документации, вероятно, из-за особого характера Sized
: она всегда автоматически выводится для всех типов, где это применимо, и эта реализация не может быть добавлена или отменена (в отличие от Send
и Sync
) .
Если это не учитывать, инкапсуляция другого интеллектуального указателя в Box
не принесет особой пользы. Если есть намерение переместить фактический интеллектуальный указатель (Rc
) через границу C FFI и обратно, нужно иметь в виду только одну вещь: макет Rc<T>
несовместим с необработанным указателем. , даже если T
равно Sized
( в отличие от Box<T>
).
Следовательно, нам нужно явно преобразовать его в необработанный указатель и обратно. Функции into_raw
и from_raw
также доступны для Rc
.
/// create a new Foo and give it to caller
#[no_mangle]
pub extern "C" fn foo_new() -> *const RefCell<Foo> {
Rc::into_raw(Rc::new(RefCell::new(Foo { glonk: false })))
}
/// clone the pointers into two
#[no_mangle]
pub extern "C" fn foo_clone(foo: *const RefCell<Foo>) -> (*const RefCell<Foo>, *const RefCell<Foo>) {
unsafe {
let ptr = Rc::from_raw(foo);
let c = Rc::clone(ptr);
(ptr, c)
}
}
/// get a property of a Foo without returning ownership
#[no_mangle]
pub extern "C" fn foo_glonk(foo: *const RefCell<Foo>) -> bool {
unsafe { (*foo).borrow().glonk }
}
/// return ownership of the Foo,
/// so it can be freed in Rust-land
#[no_mangle]
pub extern "C" fn foo_return(foo: *const RefCell<Foo>) {
let _ = Rc::from_raw(foo);
}