首页 > 解决方案 > 如何在递归 std::ops::Deref 上绑定类型?

问题描述

我想根据可以通过 deref 强制访问的函数来绑定类型。问题是对 Deref 的限制仅适用于一级强制。


struct A {}

impl A {
    fn foo(&self) {
        println!("foo");
    }
}

struct B {}

impl Deref for B {
    type Target = A;
    fn deref(&self) -> &Self::Target {
        &A{}
    }
}

struct C {}

impl Deref for C {
    type Target = B;
    fn deref(&self) -> &Self::Target {
        &B{}
    }
}

fn call_with_ref(obj: &A) {
    print!("call_with_ref: ");
    obj.foo();
}

fn checked_call_with_ref(obj: &A) {
    let ptr: *const A = obj;
    if !ptr.is_null() {
        print!("checked_call_with_ref: ");
        obj.foo();   
    } else {
        println!("checked_call_with_ref: null")
    }
}

fn call_with_pointer<T: Deref<Target = A>>(ptr: *const T) {
    if !ptr.is_null() {
        print!("call_with_pointer: ");
        unsafe { (*ptr).foo() };   
    }
}

fn main() {
    let c = C{};
    let ref_to_c = &c;
    let mut ptr_to_c: *const C = ref_to_c;
    ref_to_c.foo(); // works
    call_with_ref(ref_to_c); // works
    // call_with_pointer(ptr_to_C); // does not work bec. it derefs to B

    unsafe { checked_call_with_ref(&*ptr_to_c) }; // works on non-nulls
    ptr_to_c = std::ptr::null();
    unsafe { checked_call_with_ref(&*ptr_to_c) }; // undefined behavior on null pointers

    // have to put null check on each call site
    if let Some(ref_to_obj) = unsafe { ptr_to_c.as_ref() } {
        call_with_ref(ref_to_obj);
    }
}

锈游乐场

这里的 foo 函数仅由A. Refs toB可以通过直接强制调用它,而 refs toC仍然可以通过 deref-ing 到 B 调用它。Deref<Target = A>不是作为Cimplements的正确绑定Deref<Target = B>。Rust 有什么Coercible特点吗?

标签: rust

解决方案


Deref编译器会自动应用强制转换,因此很少有任何理由将其设为显式绑定。只写call_foo接受&A

fn call_foo(obj: &A) {
    print!("Call from fn: ");
    obj.foo();
}

也可以看看


推荐阅读