如何将引用元组转换为元组的引用?

时间:2019-06-10 14:47:51

标签: reference rust

我想将一个引用的元组(全部是对同一结构的成员的引用)转换为一个元组的引用。

我试图以各种方式胁迫他们,但是我无法不克隆而这么做。

struct Bar();

struct Foo(Bar, Bar, Bar);

fn main() {
    let a: &Foo = &Foo(Bar(), Bar(), Bar());
    let b: &(Bar, Bar) = &(a.0, a.1);
}
error[E0507]: cannot move out of borrowed content
 --> src/main.rs:7:28
  |
7 |     let b: &(Bar, Bar) = &(a.0, a.1);
  |                            ^^^ cannot move out of borrowed content

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:7:33
  |
7 |     let b: &(Bar, Bar) = &(a.0, a.1);
  |                                 ^^^ cannot move out of borrowed content

鉴于b的类型为&(Bar, Bar),我希望a的类型为&Foo

1 个答案:

答案 0 :(得分:4)

这是不可能的。

引用引用表示一个值。您希望有一个&(Bar, Bar),但是在内存中没有任何地方有2元组的(Bar, Bar)。您不能引用不存在的内容。

&(A, B)(&A, &B)的内存布局本质上是不兼容的,因此您也不能使用不安全的Rust技术。


在这种特殊情况下,您可能可以使用不安全的Rust将您的&Foo直接转换为&(Bar, Bar),但是。

  • 它要求元组结构和元组的布局相同;我不知道可以保证 1
  • 它要求将元组结构的布局紧密包装,以便您可以偏移成员大小才能到达下一个;我不知道可以保证 1
  • 它要求元组结构的布局按照定义的顺序放置成员。我不知道可以保证 1
  • 您只能对连续的片段执行此操作;没有得到第一项和第三项
// 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 -实际上,reference explicitly states

  

Tuples对其布局没有任何保证。

     

例外情况是单位元组(()),它被保证为零大小类型,其大小为0,对齐方式为1。

这意味着尽管此代码可能会打印出您期望的内容,并且Miri不会抱怨,但这是未定义的行为。