This is impossible.
A reference refers to a value. You wish to have a &(Bar, Bar)
but there is nowhere in memory that has a 2-tuple of (Bar, Bar)
. You cannot refer to something that does not exist.
The memory layouts of &(A, B)
and (&A, &B)
are fundamentally incompatible, so you cannot use unsafe Rust techniques either.
In this particular case, you might be able to use unsafe Rust to convert your &Foo
directly to a &(Bar, Bar)
, but...
- it requires that the layout of a tuple struct and a tuple be the same; I don't know that's guaranteed1
- it requires that the layout of a tuple struct be tightly packed such that you can offset by the member size to get to the next one; I don't know that's guaranteed1
- it requires that the layout of the tuple struct places the members in the same order they are defined; I don't know that's guaranteed1
- you can only do it for sequential pieces; no getting the first and third item
// I copied this unsafe block from Stack Overflow
// without properly documenting why I think this code is safe.
let b: &(Bar, Bar) = unsafe { &*(a as *const Foo as *const (Bar, Bar)) };
println!("{:?}", b);
// I copied this unsafe block from Stack Overflow
// without properly documenting why I think this code is safe.
let c: &(Bar, Bar) = unsafe {
let p = a as *const Foo as *const Bar;
let p = p.offset(1);
&*(p as *const (Bar, Bar))
};
println!("{:?}", c);
1 — In fact, the reference explicitly states:
Tuples do not have any guarantees about their layout.
The exception to this is the unit tuple (()
) which is guaranteed as a zero-sized type to have a size of 0 and an alignment of 1.
This means that while this code may print out what you expect and Miri does not complain, it's undefined behavior.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…