我正在实施BTreeMap<K, V>的替代方案.在此之上,我正在构建一个BTreeSet,它是一个围绕type MyBTreeSetContents<T> = MyBTreeMap<T, ()>的包装器.

在内部,该BTree的叶 node 包含Vec<(K, V)>个值. 在BTreeSet的情况下,这就变成了Vec<(K, ())>.

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

因此,问题是:

  • K(K, )(K, ())的内存表示法是否相同?
  • 因此,在(K, ())K之间转化是可以的吗?
  • 推而广之,把Vec<(K, ())>改成Vec<K>行吗?

如果有其他方法可以避免std::mem::transmute人的使用,当然也会非常感激!

推荐答案

No.就目前执行的情况而言,不能保证将(T, ())人转化为T人.元组使用默认表示,除了The Rust Reference中所说的以外,这并不意味着布局的任何内容.只有#[repr(transparent)]个能保证布局兼容性.


然而,它可能会奏效,并可能最终得到保证.从不安全代码指南中的Structs and Tuples开始:

一般说来,N的匿名元组类型(T1..Tn)的布局就好像有相应的元组 struct 一样……

...

对于 struct 布局1-ZST[1]字段被忽略.

具体地说,如果除一个字段外的所有字段都是1-ZST,则该 struct 等价于单字段 struct .换句话说,如果除一个字段之外的所有字段都是1-ZST,则整个 struct 与该字段具有相同的布局.

例如:

type Zst1 = ();
struct S1(i32, Zst1); // same layout as i32

[1]大小为零的类型称为零大小类型,缩写为"ZST".本文还使用了"1-ZST"缩写,代表"一对齐零大小类型",指的是对齐要求为1的零大小类型.

如果我对这一点的理解是正确的,(K, ())的布局与K相同,因此可以安全地变形.然而,这不会扩展到像《RustonomicalTransmutes》中提到的那样,将Vec<T>转化为Vec<U>:

即使是同一泛型类型的不同实例也可能具有非常不同的布局.Vec<i32>Vec<u32> might的字段顺序相同,也可能不同.

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

Rust相关问答推荐

Rust,polars CSV:有没有一种方法可以从impll BufRead(或任何字节迭代器)中读取CSV?

空字符串转换为Box字符串时是否分配?<>

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

获取已知数量的输入

为什么 vec![Vec::with_capacity(n)] 为子向量创建 0 容量?

为什么`tokio::main`可以直接使用而不需要任何导入?

为什么 Rust 创建的 f32 小于 f32::MIN_POSITIVE?

使用 Option 来分配?

std::vector::shrink_to_fit 如何在 Rust 中工作?

Some(v) 和 Some(&v) 有什么区别?

Rust 生命周期:这两种类型声明为不同的生命周期

具有在宏扩展中指定的生命周期的枚举变体数据类型

强制特征仅在 Rust 中的给定类型大小上实现

Rust 将特性传递给依赖项

在 Rust 中,将可变引用传递给函数的机制是什么?

预期类型参数,发现不透明类型

当 `T` 没有实现 `Debug` 时替代 `unwrap()`

Rust:如果我知道只有一个实例,那么将可变borrow 转换为指针并返回(以安抚borrow 判断器)是否安全?

返回 &str 但不是 String 时,borrow 时间比预期长

守卫如何影响匹配语句?