将 (T, ()) 转换为 T 安全吗?

Qqw*_*qwy 2 tuples data-representation rust transmute

我正在实施BTreeMap<K, V>. 在此之上,我正在构建一个 BTreeSet,它是type MyBTreeSetContents<T> = MyBTreeMap<T, ()>.

在内部,此 BTree 的叶节点包含一系列Vec<(K, V)>值。对于 BTreeSet,这因此成为一个Vec<(K, ())>.

我想提供一个对 BTreeSet 中值的引用的快速迭代器。产生 的迭代器&T。但到目前为止,我能在不进行 transmute 的情况下得到的最好结果是生成&(T, ()).

因此问题是:

  • K(K, )和 的内存表示(K, ())相同吗?
  • 因此可以在(K, ())和之间转换吗K
  • 通过扩展,可以将 转换Vec<(K, ())>为 a吗Vec<K>

如果有其他方法可以规避std::mem::transmuteall-together 的使用,那么我们当然也会非常感激!

kmd*_*eko 6

不。就目前强制执行的内容而言,不能保证转变(T, ())为。元组使用默认表示,除了The Rust ReferenceT中所述之外,它不暗示任何有关布局的内容。只会保证布局兼容性。#[repr(transparent)]


然而,它可能会起作用并且最终可能得到保证。来自不安全代码指南中的结构体和元组:

一般来说,元数为(T1..Tn)N 的匿名元组类型的布局“就好像”有一个相应的元组结构......

...

出于结构布局的目的,忽略1-ZST [1]字段。

特别是,如果除一个字段之外的所有字段都是 1-ZST,则该结构相当于单字段结构。换句话说,如果除一个字段之外的所有字段都是 1-ZST,则整个结构体具有与该字段相同的布局。

例如:

type Zst1 = ();
struct S1(i32, Zst1); // same layout as i32
Run Code Online (Sandbox Code Playgroud)

[1] 大小为零的类型称为零大小类型,缩写为“ZST”。本文档还使用“1-ZST”缩写,代表“一对齐零大小类型”,指对齐要求为 1 的零大小类型。

如果我对此的理解是正确的,(K, ())则具有等效的布局K,因此可以安全地进行转换。然而,这不会扩展到转化Vec<T>为Rustonomicon 中的转化Vec<U>中提到的:

即使同一泛型类型的不同实例也可能具有截然不同的布局。它们的字段的顺序可能相同,也可能不同Vec<i32>Vec<u32>

不幸的是,你应该对此持保留态度。不安全代码指南旨在推荐unsafe代码可以依赖的内容,但目前它仅将自己宣传为正在进行的工作,并且对语言规范的任何具体补充都将移至官方 Rust 参考。我说这“可能会起作用”,因为指南的一个方面是记录当前的行为。但到目前为止,参考文献中还没有提到这样的保证。