如何在结构中分配 impl 特征?

tun*_*ten 5 rust

考虑一些不可访问但实现 API 特征的结构 (HiddenInaccessibleStruct)。获取此隐藏类型的对象的唯一方法是调用返回此类型的不透明实现的函数。另一个结构体拥有某种类型,它利用了这个 API 特征。目前,似乎无法在fn new(). 下面的代码也可以在 Rust Playgrounds中找到。

// -- public api 
trait Bound {
    fn call(&self) -> Self;
}

// this is not visible

#[derive(Default)]
struct HiddenInaccessibleStruct;

impl Bound for HiddenInaccessibleStruct {
    fn call(&self) -> Self { }
}

// -- public api
pub fn load() -> impl Bound {
    HiddenInaccessibleStruct::default()
}

struct Abc<T> where T : Bound {
    field : T
}

impl<T> Abc<T> where T : Bound {
    
    pub fn new() -> Self {
        let field = load();
        
        Abc {
            field // this won't work, since `field` has an opaque type.
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

更新 API 特征 Bound 声明了一个函数,该函数返回 Self,因此它没有调整大小。

use*_*968 6

这里的空中碰撞有两个概念:通用类型和存在类型。AnAbc<T>是一个通用类型,我们,包括Abc,可以指代任何T实际的类型T(就这么简单)。impl Trait-types 是 Rust 最接近存在类型的方法,我们只承诺这样的类型存在,但我们不能引用它(没有T解决方案)。这也意味着您的构造函数实际上无法创建Abc<T>,因为它无法决定是什么T。另请参阅这篇文章

T一种解决方案是将问题解决在楼上:更改构造函数以从外部获取 a ,并将值传递给它:

impl<T> Abc<T>
where
    T: Bound,
{
    pub fn new(field: T) -> Self {
        Abc { field }
    }
}

fn main() {
    let field = load();
    let abc = Abc::new(field);
}
Run Code Online (Sandbox Code Playgroud)

看看这个游乐场

这是可行的,但它只是转移了问题:abcin的类型main()Abc<impl Bound>,(目前)不可能写下来。如果您将该行更改为let abc: () = ...,编译器会抱怨您正在尝试分配Abc<impl Bound>()。如果您尝试遵循建议并将该行更改为let abc: Abc<impl Bound> = ...,编译器将抱怨该类型无效。abc所以你必须留下暗示的类型。这带来了一些可用性问题Abc<impl Bound>,因为您无法轻松地将该类型的值放入其他结构等中;基本上,存在类型“感染”包含它的外部类型。

impl Trait-类型主要用于立即使用,例如impl Iterator<Item=...>. 就您而言,显然目的是隐藏类型,您可能会逃脱seal 的惩罚 Bound。在更一般的情况下,使用动态调度()可能会更好Box<dyn Bound>