指向特征的指针

moa*_*lon 4 pointers ffi traits rust

当我开始学习 Rust 时,我天真地假设 Rust 指向特征的指针就像 C++ 指向基类的指针一样实现,并编写了一些即使在这种假设下也能工作的代码。具体来说,我编写的代码与需要读取和查找流的 FFI 库接口,如下所示:

struct StreamParts {
    reader: *mut Read,
    seeker: *mut Seek,
}

fn new_ffi_object<T: Read + Seek + 'static>(stream: T) -> FFIObject {
    let stream_ptr   = Box::into_raw(Box::new(stream));
    let stream_parts = Box::into_raw(Box::new(StreamParts {
        reader: stream_ptr as *mut Read,
        seeker: stream_ptr as *mut Seek,
    }));

    ffi_library::new_object(stream_parts, ffi_read, ffi_seek, ffi_close)
}

extern "C" fn ffi_read(stream_parts: *mut StreamParts, ...) -> c_ulong {
    (*stream_parts.reader).read(...)
    ...
}

extern "C" fn ffi_seek(stream_parts: *mut StreamParts, ...) -> c_ulong {
    (*stream_parts.seeker).seek(...)
    ...
}

extern "C" fn ffi_close(stream_parts: *mut StreamParts) {
    mem::drop(Box::from_raw(stream_parts.reader));
    mem::drop(Box::from_raw(stream_parts));
}
Run Code Online (Sandbox Code Playgroud)

它奏效了。但是,我不完全理解其工作原理的三件事:

  1. Rust 的特征对象很胖,包含两个指针。因此,与 C++ 不同,*mut Read它是指向特征对象的指针,对吗?这个 Trait 对象分配在哪里?Rust 文档没有涉及这个具体案例。
  2. 我的假设是否正确,mem::drop(Box::from_raw(stream_parts.reader))完全丢弃原始流?
  3. 为什么'static需要在new_ffi_object()

oli*_*obk 5

指针和引用的行为完全相同,除了借用检查器禁止您拥有悬空引用以及您需要将指针解除引用包装到块中这一事实之外unsafe

  1. 所以是的,sizeof::<*mut Read>() == sizeof::<*mut ()>() * 2. 特征对象没有分配到任何地方。它只不过是一个具有两个字段的结构。一种是指向数据的指针,另一种是指向 vtable 的指针。vtable分配在静态内存中。
  2. 正确的。它访问 的 vtable 指针并在 vtable 中reader查找impl。drop
  3. 如果您没有'static生命周期,则您T可能包含生命周期短于 的引用'static。生命周期限制说的是T没有这样的引用,因此可以不受限制地复制到任何地方,甚至在堆上。