Как преобразовать кортеж ссылок в ссылку на кортеж? - PullRequest
0 голосов
/ 10 июня 2019

Я хотел бы преобразовать кортеж ссылок (которые являются ссылками на элементы одной и той же структуры) в ссылку на кортеж.

Я пытался заставить их разными способами, однако я не смог сделать это без клонирования.

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 Ответ

4 голосов
/ 10 июня 2019

Это невозможно.

Ссылка ссылается на значение.Вы хотите иметь &(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 - Фактически, ссылка явно заявляет :

Кортежи не имеют никаких гарантий относительно их макета.

Исключением является кортеж модуля (()), который гарантированно имеет тип нулевого размера с размером 0.и выравнивание 1.

Это означает, что хотя этот код может распечатать то, что вы ожидаете, и Мири не жалуется, это неопределенное поведение.

...