Какой лучший способ конвертировать [[T; 4]; 3] в [Т; 12]?
Как я понимаю, [[T; 4]; 3]
и [T; 12]
имеют одинаковое расположение в памяти. Каков наилучший способ преобразовать значение между этими типами? Могу ли я преобразовать ссылку на одну ссылку на другую? Могу ли я избежать копирования всех элементов? Нужно ли мне unsafe
?
2 ответа
Да, вы можете преобразовать ссылку в [[T; 4]; 3]
в ссылку на [T; 12]
, но только с небезопасным кодом, используя mem::transmute
, Лучше всего обернуть это в функцию, чтобы полученной ссылке был назначен правильный срок службы, иначе transmute
позволит получить ссылку с большим временем жизни, чем должна иметь ссылка.
fn convert<'a>(a: &'a [[u8; 4]; 3]) -> &'a [u8; 12] {
unsafe { std::mem::transmute(a) }
}
Это может быть сокращено благодаря правилам жизненного цикла:
fn convert(a: &[[u8; 4]; 3]) -> &[u8; 12] {
unsafe { std::mem::transmute(a) }
}
Хотя при работе с небезопасным кодом я бы понял, если бы вы предпочли более явную версию!
Отказ от ответственности: Я не очень хорошо разбираюсь в низкоуровневой стороне Rust, я не знаю, что считается "хорошей практикой" в низкоуровневом Rust. Совет, данный здесь, не может быть хорошими идеями. Я кладу их сюда, потому что... ну, они работают.
Вы могли бы трансмутировать их. Проблема в том, что это будет копия, в документации сказано, что это эквивалент memcpy
вызов. Это не то, что вы хотели, но здесь это все равно:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = unsafe { std::mem::transmute::<[[u8; 4]; 3], [u8; 12]>(a) };
println!("c: {:?}", c);
}
Другой вариант - работать с необработанным указателем:
fn main() {
let a: [[u8; 4]; 3] = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]];
let b: [u8; 12] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
println!("a: {:?}", a);
println!("b: {:?}", b);
let c = &a as *const _ as *const [u8; 12];
// Or it can be this: let c = &mut a as *mut [[u8; 4]; 3];
for i in 0..12 {
let p = c as *const u8;
let v = unsafe { *p.offset(i) };
println!("{}", v);
}
}
что тоже не особенно здорово.
Указатель также может быть указателем или изменяемым указателем на тот же тип (так как &mut T
может быть приведен к *mut T
), и приведенный выше код работает точно так же (с a
помечен как изменяемый):
let c = &mut a as *mut [[u8; 4]; 3];
Я действительно задаюсь вопросом, является ли это чем-то вроде проблемы XY. Может быть, способ работы с вашими данными может быть изменен, чтобы не требовать этого?