当类型在结构定义中显式指定时,无法推断类型参数 T 的类型

cor*_*nus 8 pointers non-nullable rust

我有一个结构定义,其中包括以下字段:

pub struct Separated<'a, I, T>
{
    ..., // other fields,
    separated: NonNull<dyn 'a + Iterator<Item = T>>,
}
Run Code Online (Sandbox Code Playgroud)

不久之后,在其构造函数中,我尝试将该字段初始化为悬空指针:

let sep = Separated {
    ..., // other fields
    separated: NonNull::dangling(),
};
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这会产生此错误:

error[E0282]: type annotations needed
   |
16 |             separated: NonNull::dangling(),
   |                        ^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
Run Code Online (Sandbox Code Playgroud)

这个领域没有什么神秘之处。它的类型在结构定义中明确设置。我不明白为什么类型推断器不能推断出合适的类型来注入那里。

可以在下方和操场上找到产生此错误的最小 20 行示例:

use std::pin::Pin;
use std::ptr::NonNull;

pub struct Separated<'a, T> {
    t: &'a T,
    separated: NonNull<dyn 'a + Iterator<Item = T>>,
}

impl<'a, T> Separated<'a, T>
where
    T: 'a + Copy + PartialEq,
{
    fn new(t: &'a T) -> Pin<Box<Self>> {
        let sep = Separated {
            t,
            separated: NonNull::dangling(),
        };
        unimplemented!()
    }
}
Run Code Online (Sandbox Code Playgroud)

我确实需要separated一个指向 trait 对象而不是单态类型的指针:它将包含的真正 trait 对象由一堆迭代器组合子组成,包括像Mapand这样的组合子,它们TakeWhile的类型包括函数指针,因此是不可命名的。

NonNull::dangling不是参数函数:NonNull<T>结构是参数的,但这个函数不是。因此,我不能只是通过涡轮钓鱼来摆脱这种情况。我完全不知道如何提供类型注释。


上下文,如果有用:我走这条路的全部原因是我试图创建一个迭代器组合器,为所有合适的迭代器自动实现,它在原始迭代器的每个 N 元素之间注入一个元素。对于单个迭代器来说,实现起来并不那么困难,但作为通用组合器要做到这一点要困难得多,因为IntoChunksItertools 的chunks()组合器生成的结构体本身不是迭代器,只是一个实现 的结构体IntoIterator。因此,我们需要跟踪IntoChunks结构以及它产生的迭代器。

我采用的方法是创建一个自引用结构,Separated,其中包含这两者。假设结构总是固定的,这应该是安全的。然后我impl Iterator for Separated只是将next调用推迟到self.separated.

Frx*_*rem 5

根据标准文档,的定义NonNull::dangling()是这样的:

impl<T> NonNull<T> {
  pub const fn dangling() -> NonNull<T> {
    /* ... */
  }
}
Run Code Online (Sandbox Code Playgroud)

并且在您的代码中,您在一个带有 type 的表达式的地方使用它NonNull<dyn 'a + Iterator<Item = T>>,因此返回值必须具有这种类型。

这里的微妙之处在于泛型类型参数具有隐式Sized边界(除非它具有?Sized边界)。所以因为 的实现NonNull::dangling没有?Sized界限,Rust 会尝试NonNull根据这些要求推断出 的类型参数:

  • 因为该NonNull::<T>::dangling()方法没有 bound T: ?Sized,所以只为 sized types 实现T,并且类型参数必须是 sized 。
  • 类型参数必须是dyn 'a + Iterator<Item = T>.

然而,由于 trait 对象(“dyn Trait类型”)没有大小,Rust 不可能同时满足这两个要求,因此它“无法推断类型参数的类型T”。


事实上,通过将类型显式添加到您的 Playground 示例中,您将收到一条不同的错误消息,该消息更明确地说明了该问题:

let sep = Separated::<'a, T> {
  t,
  separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
};
Run Code Online (Sandbox Code Playgroud)
error[E0599]: no function or associated item named `dangling` found for type `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>` in the current scope
  --> src/lib.rs:16:64
   |
16 |             separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
   |                                                                ^^^^^^^^ function or associated item not found in `std::ptr::NonNull<(dyn std::iter::Iterator<Item = T> + 'a)>`
   |
   = note: the method `dangling` exists but the following trait bounds were not satisfied:
           `dyn std::iter::Iterator<Item = T> : std::marker::Sized`
Run Code Online (Sandbox Code Playgroud)