让我先说一句,我正在积极地寻找除了transmute
之外的其他选项,我只是惊讶于transmute
在这种情况下无法编译。
我正在开发一个Builder
派生库,它在编译时检查哪些字段被初始化。为此,我使用const泛型。我得到了基本的工作,但我试图添加一个功能,因为我正在寻找transmute
。
如果我使用transmute
,setter的示例如下所示:
#[derive(Builder)]
pub struct Foo<const SIZE: usize> {
bar: [usize; SIZE],
}
// Just the setter part of the macro expansion:
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn bar(mut self, bar: [usize; SIZE]) -> FooBuilder<SIZE, true> {
self.data.bar = Some(bar);
unsafe { std::mem::transmute(self) }
}
}
但转化不是这样的。SIZE
是完全相同的,布尔值对底层数据没有任何影响,但我仍然得到:
cannot transmute between types of different sizes, or dependently-sized types
source type: `test::const_generic::FooBuilder<SIZE, false>` (size can vary because of [usize; SIZE])
target type: `test::const_generic::FooBuilder<SIZE, true>` (size can vary because of [usize; SIZE])
我只是好奇为什么会有这样的限制。有人能给我解释一下吗?
// simplified macro expansion:
pub struct Foo<const SIZE: usize> {
bar: [usize; SIZE],
}
impl <const SIZE: usize> Foo<SIZE> {
fn builder() -> FooBuilder<SIZE, false> {
FooBuilder::new()
}
}
pub struct FooBuilder<const SIZE: usize, const __BUILDER_CONST: bool> {
bar: Option<[usize; SIZE]>,
}
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn new() -> FooBuilder<SIZE, false> {
FooBuilder {
bar: None,
}
}
}
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn bar(mut self, bar: [usize; SIZE]) -> FooBuilder<SIZE, true> {
self.bar = Some(bar);
unsafe { std::mem::transmute(self) }
// ^ Should work, because the value of `__BUILDER_CONST` has no influence
// on the layout of the struct, and `SIZE` is identical
}
}
impl<const SIZE: usize> FooBuilder<SIZE, true> {
pub fn build(self) -> Foo<SIZE> {
Foo::<SIZE> {
bar: self.bar.unwrap()
}
}
}
顺便说一句,实际的setter看起来更像是这样,我只是在添加一个新特性时遇到了一些奇怪的生命周期问题(使用impl AsRef<T>
作为setter输入类型)
impl<const SIZE: usize> FooBuilder<SIZE, false> {
pub fn bar(self, bar: [usize; SIZE]) -> FooBuilder<SIZE, true> {
let mut data = self.data;
data.bar = Some(bar);
FooBuilder { data }
}
}
1条答案
按热度按时间iyr7buue1#
编译器中的分析限制太多了。它不允许任何依赖于动态大小的转换,即使我们可以证明大小相等。
但是,请注意,在您的情况下,转换是不正确的:你需要把
#[repr(transparent)]
添加到结构体中。