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

pub struct Separated<'a, I, T>
{
    ..., // other fields,
    separated: NonNull<dyn 'a + Iterator<Item = T>>,
}

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

let sep = Separated {
    ..., // other fields
    separated: NonNull::dangling(),
};

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

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

这个领域没有什么神秘之处;其类型在 struct 定义中显式设置.我不明白为什么类型推断器不能推断出一个合适的类型来注入那里.

下面和on the playground中可以找到产生此错误的最少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!()
    }
}

我确实需要separated作为指向一个trait对象的指针,而不是一个单形类型:它将包含的真正trait对象由一组迭代器组合器组成,包括MapTakeWhile这样的迭代器组合器,它们的类型包括函数指针,因此是不可测量的.

NonNull::dangling不是参数化函数:NonNull<T> struct 是参数化的,但此函数不是.因此,我不能只是用鱼来摆脱这一切.我完全不知道该如何提供类型注释.


上下文,如果有用的话:我走这条路的全部原因是我试图创建一个迭代器组合器,为所有适当的迭代器自动实现,它在源迭代器的每N个元素之间注入一个元素.对于单个迭代器来说,这并不是很难实现,但作为一个通用的组合器要困难得多,因为Itertools的chunks() combinator生成的IntoChunks struct 本身并不是一个迭代器,只是一个实现IntoIterator的 struct .因此,我们需要跟踪IntoChunks struct 及其生成的迭代器.

我采用的方法是创建一个自引用 struct Separated,它包含这两个元素.假设 struct 始终处于固定状态,这应该是安全的.然后我拨打impl Iterator for Separated,把next个电话推迟到self.separated个.

推荐答案

根据标准文件,NonNull::dangling()的定义如下:

impl<T> NonNull<T> {
  pub const fn dangling() -> NonNull<T> {
    /* ... */
  }
}

在代码中,使用它的地方是一个类型为NonNull<dyn 'a + Iterator<Item = T>>的表达式,因此返回值必须是这种类型.

这里的微妙之处在于泛型类型参数有一个隐式的Sized界(除非它有一个?Sized界).因此,由于NonNull::dangling的实现没有?Sized界限,Rust将try 根据以下要求推断NonNull的类型参数:

  • 因为NonNull::<T>::dangling()方法没有边界T: ?Sized,所以它只对大小为T的类型实现,并且类型参数必须大小为.
  • 类型参数必须为dyn 'a + Iterator<Item = T>.

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


事实上,通过显式地将该类型添加到playground 示例中,您将得到一条关于该问题的更明确的错误消息:

let sep = Separated::<'a, T> {
  t,
  separated: NonNull::<dyn 'a + Iterator<Item = T>>::dangling(),
};
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`

Rust相关问答推荐

如何从Rust记录WASM堆内存使用情况?

为什么我需要在这个代码示例中使用&

包含嵌套 struct 的CSV

如何在Rust中实现Functor trait?

有没有办法在Rust中配置常量变量的值?

有没有办法指定只在Rust的测试中有效的断言?

为什么铁 rust S似乎有内在的易变性?

Rust&;Tokio:如何处理更多的信号,而不仅仅是SIGINT,即SIGQUE?

在生存期内将非静态可变引用转换为范围内的静态可变引用

使用关联类型重写时特征的实现冲突

使用Rust WASM读取文件

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

确保参数是编译时定义的字符串文字

borrow 是由于对 `std::sync::Mutex>` 的解引用强制而发生的

为什么在 Allocator API 中 allocate() 使用 `[u8]` 而 deallocate 使用 `u8` ?

通过mem::transmute将数组展平安全吗?

如何获取包裹在 Arc<> 和 RwLock<> 中的 Rust HashMap<> 的长度?

通用函数中的生命周期扣除和borrow (通用测试需要)

有没有更好的方法来为拥有 DIsplay 事物集合的 struct 实现 Display?

使用 rust-sqlx/tokio 时如何取消长时间运行的查询