gpt4 book ai didi

rust - 转化 PhantomData 标记安全吗?

转载 作者:行者123 更新时间:2023-11-29 07:46:53 24 4
gpt4 key购买 nike

这是拍摄 out of context所以看起来有点奇怪,但我有以下数据结构:

use std::marker::PhantomData;

pub struct Map<T, M=()> {
data: Vec<T>,
_marker: PhantomData<fn(M) -> M>,
}

Map 是一个关联映射,其中键被“标记”以防止在另一个不相关的映射上使用来自一个映射的键。用户可以通过传递他们制作的一些独特类型作为 M 来选择加入此功能,例如:

struct PlayerMapMarker;
let mut player_map: Map<String, PlayerMapMarker> = Map::new();

这一切都很好,但是我想为这个 map 编写的一些迭代器(例如只给出值的迭代器)在它们的类型中不包含标记。下面的转化可以安全地丢弃标记吗?

fn discard_marker<T, M>(map: &Map<T, M>) -> &Map<T, ()> {
unsafe { std::mem::transmute(map) }
}

这样我就可以编写和使用:

fn values(&self) -> Values<T> {
Values { inner: discard_marker(self).iter() }
}

struct Values<'a, T> {
inner: Iter<'a, T, ()>,
}

最佳答案

长话短说: 添加 #[repr(C)]你应该很好。


这里有两个不同的问题:转换在返回类型返回有效数据的意义上是否有效,以及整个事情是否违反了可能附加到所涉及类型的任何更高级别的不变量。 (在我的 blog post 的术语中,您必须确保保持有效性和安全不变性。)

对于有效性不变量,您处于未知领域。编译器可以决定布局 Map<T, M>Map<T, ()> 截然不同,即 data字段可能处于不同的偏移量并且可能存在虚假填充。这似乎不太可能,但到目前为止我们在这里保证很少。关于我们可以和想要保证的内容的讨论happening right now .我们有意避免对 repr(Rust) 做出太多保证。以免把自己逼到墙角。

你可以做的是添加 repr(C)到你的结构,那么我相当确定你可以指望 ZST 不会改变任何东西(但我 asked for clarification 只是为了确定)。对于 repr(C)我们为结构的布局提供了更多保证,这实际上是它的全部目的。如果您想玩弄结构布局,您可能应该添加该属性。

对于更高级别的安全不变量,您必须小心不要创建损坏的 Map并让那个“泄漏”超出你的 API 的边界(进入周围的安全代码),即你不应该返回 Map 的实例。这违反了您可能对其施加的任何不变量。此外,PhantomData对方差和下降检查器有一些影响,你应该知道。由于正在转换的类型是如此微不足道(您的标记类型不需要删除,即它们和它们的传递字段都没有实现 Drop )我认为您不必从这方面期待任何问题。

要清楚,repr(Rust) (默认值)也可能很好,一旦我们决定这是我们想要保证的东西——并且忽略 size-0-align-1 类型(如 PhantomData )对我来说完全是一个非常明智的保证。虽然我个人仍然建议使用 repr(C)除非这有你不愿意支付的成本(例如,因为你失去了编译器通过重新排序自动减少大小并且无法手动复制它)。

关于rust - 转化 PhantomData 标记安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52911942/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com