方便地访问原始指针的成员?

时间:2016-10-28 10:04:58

标签: rust

为我们知道不需要检查NULL的实例访问原始指针的嵌套成员的符号可能相当尴尬:

struct MyLink {
    link: *mut MyLink,
}
let var = *(*(*(*root).link).link).link;

是否可以访问原始指针的结构成员而无需每次都明确地取消引用?也许通过使用像root.link().link().link()这样的方法或者包装类型?

虽然习惯性的Rust避免了这种情况,但在特殊情况下,它并不容易避免。 Rc有内存开销,借用检查器会导致链接成员出现问题,C-API可能需要指针等等。

3 个答案:

答案 0 :(得分:3)

如果这是代码中的重复出现的情况,我只想创建一个通用的包装器。

   connect_args={ "cursor_factory": MyCursor }

我们在构造时声明#[repr(C)] #[derive(Hash)] struct Ptr<T> { ptr: *mut T } impl<T> Ptr<T> { pub unsafe fn new(ptr: *mut T) -> Ptr<T> { debug_assert!(!ptr.is_null()); Ptr { ptr: ptr } } #[inline(always)] pub fn as_pointer(&self) -> *mut T { self.ptr } } impl<T> Deref for Ptr<T> { type Target = T; #[inline(always)] fn deref(&self) -> &T { unsafe { &*self.ptr } } } impl<T> DerefMut for Ptr<T> { #[inline(always)] fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.ptr } } } impl<T> Copy for Ptr<T> { } impl<T> Clone for Ptr<T> { #[inline(always)] fn clone(&self) -> Ptr<T> { *self } } impl<T> PartialEq for Ptr<T> { fn eq(&self, other: &Ptr<T>) -> bool { self.ptr == other.ptr } } 实际上不是null,因此我们不必在解除引用时再次检查。

然后我们在调用方法或访问属性时让语言检查ptr / Deref

DerefMut

答案 1 :(得分:1)

包装器方法确实可以提高该代码的可读性。只需按照The Book

struct MyLink {
    link: *mut MyLink,
    pub n: i32,
}

impl MyLink {
    pub unsafe fn link(&self) -> &MyLink {
        &*self.link
    }

    pub unsafe fn mut_link(&mut self) -> &mut MyLink {
        &mut *self.link
    }
}

是否将方法原型标记为unsafe取决于您的具体情况,但实现必须位于不安全的块中:即使没有解除引用,从指针获取引用也是不安全的。< / p>

使用它:

unsafe {
    let mut l1 = MyLink {
        link: 0 as *mut MyLink,
        n: 4,
    };

    let mut l2 = MyLink {
        link: &mut l1 as *mut MyLink,
        n: 3,
    };
    let n1 = l2.n;
    let n2 = l2.link().n;
    println!("{} -> {}", n1, n2);
}

Gist

答案 2 :(得分:1)

您可以使用与任何其他Rust类型完全相同的方式为原始指针实现自定义方法:

trait WickedRef<T>{
    unsafe fn wicked_ref<'x>(self) -> &'x T;
}

impl<T> WickedRef<T> for *mut T{
    unsafe fn wicked_ref<'x>(self) -> &'x T{
        &*self
    }    
}

root.link.wicked_ref().link.wicked_ref()