repr (прозрачный) не позволяет обрабатывать структуру, содержащую массив, как массив - PullRequest
0 голосов
/ 14 июня 2019

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

Как заставить этот код работать так, как он был разработан?

use std::fmt;
/// Credit Card type
#[repr(transparent)]
pub struct CreditCard([u8; 16]);

impl fmt::Display for CreditCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}{}{}{}-{}{}{}{}-{}{}{}{}-{}{}{}{}",
            self[0],
            self[1],
            self[2],
            self[3],
            self[4],
            self[5],
            self[6],
            self[7],
            self[8],
            self[9],
            self[10],
            self[11],
            self[12],
            self[13],
            self[14],
            self[15]
        )
    }
}
fn process_cc(card: CreditCard) {
    // do whatever
    println!("processed CC {}", card);
}
fn main() {
    let cc: CreditCard = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4];
    println!("cc = {}", cc);
    let card_data: [u8; 16] = [1, 2, 3, 4, 2, 2, 2, 2, 9, 8, 7, 6, 5, 5, 5, 5];
    process_cc(card_data);
}

Детская площадка

error[E0608]: cannot index into a value of type `&CreditCard`
  --> src/main.rs:11:13
   |
11 |             self[0],
   |             ^^^^^^^

...

error[E0308]: mismatched types
  --> src/main.rs:38:16
   |
38 |     process_cc(card_data);
   |                ^^^^^^^^^ expected struct `CreditCard`, found array of 16 elements
   |
   = note: expected type `CreditCard`
              found type `[u8; 16]`

1 Ответ

2 голосов
/ 14 июня 2019

Это совсем не , для чего предназначен repr(transparent). Честно говоря, я озадачен тем, что вы нашли такую ​​нишевую функцию и не прочитали документацию по ней :

Структуры с этим представлением имеют ту же компоновку и ABI, что и одно поле с ненулевым размером.

Это не имеет ничего общего с поведением типа в системе типов, только с тем, как структурирована память значения типа.

То, что вы хотите сделать, даже не относится к строго типизированному языку. Вы не можете просто присвоить массив другому типу , потому что это другой тип . С repr(transparent) допустимо преобразовывать биты из одного в другой, но это никогда не произойдет автоматически.

Лучшей альтернативой является реализация Deref и From для вашего типа:

use std::ops::Deref;

impl Deref for CreditCard {
    type Target = [u8; 16];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<[u8; 16]> for CreditCard {
    fn from(other: [u8; 16]) -> Self {
        CreditCard(other)
    }
}

Тогда возьмите любой тип, который можно превратить в CreditCard:

fn process_cc(card: impl Into<CreditCard>) {
    // do whatever
    println!("processed CC {}", card.into());
}

Смотри также:


Если бы вы были настроены на использование repr(transparent), вам нужно было бы сделать что-то вроде:

fn process_cc(card: [u8; 16]) {
    use std::mem;
    let card: CreditCard = unsafe { mem::transmute(card) };
    // do whatever
    println!("processed CC {}", card);
}

Как правило, это очень плохая идея , и весьма вероятно, что вы не должны этого делать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...