You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

需保持地址稳定的结构体的API设计方案有哪些?

强制结构体地址稳定性的API设计方案

假设有一个因某些原因需要地址稳定性的结构体,例如它包含后台线程,线程会共享其内部状态的引用。从API设计角度,我们有哪些方案可以强制实现这种地址稳定性?是否存在无需强制用户进行额外内存分配或使用MaybeUninit的方案?


现有方案的问题说明

  • 方案一:工厂函数返回Pin<Box<T>>
    让工厂函数直接返回固定指针,强制结构体仅通过固定指针被访问,但需要使用拥有所有权的指针:

    pub struct Foo {
        _pin: std::marker::PhantomPinned,
    }
    
    impl Foo {
        // 工厂函数强制固定(优点),但替调用者选择了Box作为所有权载体(缺点)。
        pub fn new() -> Pin<Box<Foo>> {
            todo!()
        }
    
        // 用户实际使用结构体时必须使用固定引用,符合预期。
        pub fn do_something(self: Pin<&Foo>) {
            todo!();
        }
    }
    

    使用Box会强制Foo在堆上单独分配内存。如果用户希望将其嵌入到另一个固定结构体中,这种额外分配就显得多余。

  • 方案二:在已固定内存位置构造结构体
    仅允许在已固定的内存位置中构造结构体:

    pub struct Bar {
        _pin: std::marker::PhantomPinned,
    }
    
    impl Bar {
        // 工厂函数接受构造Bar对象的目标位置,从一开始就强制固定(优点),避免了强制使用Box进行额外分配(优点),但同时强制调用者使用`MaybeUninit`(缺点)。
        pub fn emplace(_target: Pin<&mut MaybeUninit<Bar>>) {
            todo!()
        }
    
        // 用户实际使用结构体时必须使用固定引用,符合预期。
        pub fn do_something(self: Pin<&Bar>) {
            todo!();
        }
    }
    

    这个API可以安全使用,但容易出错。更重要的是它强制调用者必须使用MaybeUninit,且组合性不佳——无法对MaybeUninit字段进行投影,如果父结构体也采用此策略(同样需要固定),就会出现多层MaybeUninit字段。
    你也可以用Pin<&mut Option<Bar>>字段来更安全地实现,但缺点相同。

此外,某些API还会设置单独的“start”方法,但这对用户来说并不方便,且会让结构体存在可见的“未就绪”状态。我怀疑如果要避免Box分配,就无法完全避免某种形式的“未就绪”状态,但想知道是否有更便捷的方案。


内容的提问来源于stack exchange,提问作者jacobsa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 04:42:37