指向特质的指针

时间:2016-12-14 12:35:34

标签: pointers rust traits ffi

当我开始学习Rust时,我天真地认为Rust指向traits的指针就像一个指向基类的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));
}

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

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

1 个答案:

答案 0 :(得分:4)

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

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