仅用于借用检查的零宽度参考?

Zero width reference for borrow checking only?

我的目标是以零成本使用借用检查器在我的代码中强制执行不变量。但是,要使其成本为零,我似乎需要一个零宽度参考。这是上下文:

我想为一些对象创建一个工厂,用一种方法一次性使所有对象失效。

/// Example struct.
/// In my real code, there's stuff in here,
/// but its unnecessary for the question I'm asking.
struct Obj;

/// A struct that lets you build new `Obj`s
struct ObjFactory;

impl ObjFactory {
    /// makes a new object
    fn make(&self) -> Obj {
        Obj
    }

    /// enforce that there are no objects from this ObjFactory
    fn recall(&self) {
        // ?????
    }
}

我想要的规则与借用检查器执行的规则相同,所以我添加了一些虚拟引用,使借用检查器在编译时遵循不变性。

/// new placeholder struct that should take up no space
struct Dummy;

/// Example struct.
/// Now has a dummy reference so the compiler knows when to get mad
struct Obj<'a>(&'a Dummy);

/// A struct that lets you build new `Obj`s
struct ObjFactory {dummy: Dummy}

impl ObjFactory {

    /// makes a new object
    fn make(&self) -> Obj {
        // let the `Obj` immutably borrow the dummy
        Obj(&self.dummy)
    }

    /// enforce that there are no objects from this ObjFactory
    fn recall(&mut self) {
        // mutably borrow `dummy`, which means that Obj's can't borrow it anymore.
        let _borrow = &mut self.dummy;
    }
}

现在,编译器可以检测到不变量何时被破坏:

fn main() {

    // make factory
    let mut obj_factory = ObjFactory{dummy: Dummy};

    // create an object
    let obj = obj_factory.make();

    // uh oh! no objects are allowed!
    obj_factory.recall();

    // obj lasts until the end of the function
    core::mem::drop(obj);

}

recall 发生时,编译器正确检测到存在一个对象。

error[E0502]: cannot borrow `obj_factory` as mutable because it is also borrowed as immutable
 --> src/main.rs:4:5
  |
3 |     let obj = obj_factory.make();
  |               ----------- immutable borrow occurs here
4 |     obj_factory.recall();
  |     ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
5 |     core::mem::drop(obj);
  |                     --- immutable borrow later used here

这完全符合我的要求;但是,这不是零成本。即使每个 Obj 的 dummy 宽度为零,它仍然在 Obj:

中占据 space
print!("{}", std::mem::size_of::<Obj>()); // 8

我应该如何将 Obj 的 space 用法降低到 0,同时让借用检查器强制执行 ObjFactory 不变量?

您可以使用 PhantomData 来获得具有生命周期的空类型:

use core::marker::PhantomData;

/// Example struct.
struct Obj<'a>(PhantomData<&'a ()>);

/// A struct that lets you build new `Obj`s
struct ObjFactory;

impl ObjFactory {
    /// makes a new object
    fn make(&self) -> Obj<'_> {
        Obj(PhantomData) // the PhantomData has the same lifetime as `self`
    }

    /// enforce that there are no objects from this ObjFactory
    fn recall(&mut self) {}
}

fn main() {
    // make factory
    let mut obj_factory = ObjFactory;

    // create an object
    let obj = obj_factory.make();

    // uh oh! no objects are allowed!
    obj_factory.recall();

    // obj lasts until the end of the function
    core::mem::drop(obj);
}