Como posso criar uma matriz de tamanho fixo de Strings usando genéricos constantes?
Eu tenho uma função que usa uma constante genérica:
fn foo<const S: usize>() -> Vec<[String; S]> {
// Some code
let mut row: [String; S] = Default::default(); //It sucks because of default arrays are specified up to 32 only
// Some code
}
Como posso criar uma matriz de tamanho fixo de String
s no meu caso? let mut row: [String; S] = ["".to_string(), S];
não funciona porque String
não implementa o Copy
traço.
Respostas
Você pode fazer isso com MaybeUninite unsafe
:
use std::mem::MaybeUninit;
fn foo<const S: usize>() -> Vec<[String; S]> {
// Some code
let mut row: [String; S] = unsafe {
let mut result = MaybeUninit::uninit();
let start = result.as_mut_ptr() as *mut String;
for pos in 0 .. S {
// SAFETY: safe because loop ensures `start.add(pos)`
// is always on an array element, of type String
start.add(pos).write(String::new());
}
// SAFETY: safe because loop ensures entire array
// has been manually initialised
result.assume_init()
};
// Some code
todo!()
}
Claro, pode ser mais fácil abstrair tal lógica para sua própria característica:
use std::mem::MaybeUninit;
trait DefaultArray {
fn default_array() -> Self;
}
impl<T: Default, const S: usize> DefaultArray for [T; S] {
fn default_array() -> Self {
let mut result = MaybeUninit::uninit();
let start = result.as_mut_ptr() as *mut T;
unsafe {
for pos in 0 .. S {
// SAFETY: safe because loop ensures `start.add(pos)`
// is always on an array element, of type T
start.add(pos).write(T::default());
}
// SAFETY: safe because loop ensures entire array
// has been manually initialised
result.assume_init()
}
}
}
(A única razão para usar sua própria característica, em vez de Default
é que as implementações da última entrariam em conflito com aquelas fornecidas na biblioteca padrão para matrizes de até 32 elementos; eu espero que a biblioteca padrão substitua sua implementação Default
por algo semelhante ao acima, uma vez que os genéricos const tenham estabilizado).
Nesse caso, você teria agora:
fn foo<const S: usize>() -> Vec<[String; S]> {
// Some code
let mut row: [String; S] = DefaultArray::default_array();
// Some code
todo!()
}
Veja no Playground .