如何最好地提示rustc基于Pointee::Metadata的递归数据结构是良构的?

bbuxkriu  于 2023-05-22  发布在  其他
关注(0)|答案(1)|浏览(162)

Rust编译器chokes在以下代码上:

#![feature(ptr_metadata)]

use core::ptr::Pointee;

struct TypedHandle<E: ?Sized, H> {
    handle: H,
    metadata: <E as Pointee>::Metadata,
}

type NodeHandle<T, H> = TypedHandle<Node<T, H>, H>;

struct Node<T, H> {
    element: T,
    next: NodeHandle<T, H>,
    prev: NodeHandle<T, H>,
}

似乎有一个类型推断/类型解析问题,但是注解到处都是奇怪的看似不相关的建议:

error[E0284]: type annotations needed
  --> src/lib.rs:14:11
   |
14 |     next: NodeHandle<T, H>,
   |           ^^^^^^^^^^^^^^^^ cannot infer type
   |
   = note: cannot satisfy `<Node<T, H> as Pointee>::Metadata == _`
note: required because it appears within the type `TypedHandle<Node<T, H>, H>`
  --> src/lib.rs:5:8
   |
5  | struct TypedHandle<E: ?Sized, H> {
   |        ^^^^^^^^^^^
   = note: only the last field of a struct may have a dynamically sized type
   = help: change the field's type to have a statically known size
help: borrowed types always have a statically known size
   |
14 |     next: &NodeHandle<T, H>,
   |           +
help: the `Box` type always has a statically known size and allocates its contents in the heap
   |
14 |     next: Box<NodeHandle<T, H>>,
   |           ++++                +

对代码的各种更改“解决”了错误(但中断了功能):

  • 使用NonNull<E>代替<E as Pointee>::Metadata。这表明类型的递归性质并不是唯一的问题。
  • 删除TypedHandleE上的?Sized绑定。
  • 删除nextprev之一。这表明,关于next不能同时是unsized和non-last字段的注解实际上是“严重的”,尽管TypedHandle总是被调整大小。

对代码的各种更改没有帮助:

  • NodeHandle从类型别名切换到元组结构。它对错误消息也没有帮助。

到目前为止,我找到的唯一解决方案是将where NodeHandle<T, H>: Sized绑定到Node,这是 * 相当 * 笨拙的,因为这个绑定必须在之后 * 到处 * 复制。

  • 这是编译器的已知限制吗?
  • 有没有更好的方法来解决这个问题?
  • 注意:当我探索一个新的分配API时,这个问题出现在a custom implementation of LinkedList中,我通过将TypedHandle复制/粘贴到SizedHandle并删除E上的?Sized绑定来解决它,这让我感到很不舒服,但比到处复制/粘贴绑定更容易修复。
vmdwslir

vmdwslir1#

这是一个每晚的回归,@lukas-code在这个github评论中提到了我的问题。
在同一条评论中,他还提出了一个更轻量级的解决方案:添加一个_tail: ()字段,使编译器意识到一个类型的大小。
特别是,TypedHandle定义可以更改为:

struct TypedHandle<E: ?Sized, H> {
    handle: H,
    metadata: <E as Pointee>::Metadata,
    _self_is_always_sized: (),
}

以使解决方法的范围尽可能大。

相关问题