Existe uma maneira mais rápida / mais curta de inicializar variáveis ​​em uma estrutura Rust?

102

No exemplo a seguir, eu preferiria atribuir um valor a cada campo na estrutura na declaração dos campos. Como alternativa, leva efetivamente uma instrução adicional para cada campo para atribuir um valor aos campos. Tudo o que quero fazer é atribuir valores padrão quando a estrutura for instanciada.

Existe uma maneira mais sucinta de fazer isso?

struct cParams {
    iInsertMax: i64,
    iUpdateMax: i64,
    iDeleteMax: i64,
    iInstanceMax: i64,
    tFirstInstance: bool,
    tCreateTables: bool,
    tContinue: bool,
}

impl cParams {
    fn new() -> cParams {
        cParams {
            iInsertMax: -1,
            iUpdateMax: -1,
            iDeleteMax: -1,
            iInstanceMax: -1,
            tFirstInstance: false,
            tCreateTables: false,
            tContinue: false,
        }
    }
}
Brian Oh
fonte

Respostas:

162

Você pode fornecer valores padrão para sua estrutura, implementando o Defaulttrait. A defaultfunção seria semelhante à sua newfunção atual :

impl Default for cParams {
    fn default() -> cParams {
        cParams {
            iInsertMax: -1,
            iUpdateMax: -1,
            iDeleteMax: -1,
            iInstanceMax: -1,
            tFirstInstance: false,
            tCreateTables: false,
            tContinue: false,
        }
    }
}

Você pode então instanciar a estrutura fornecendo apenas os valores não padrão:

let p = cParams { iInsertMax: 10, ..Default::default() };

Com algumas pequenas alterações em sua estrutura de dados, você pode tirar proveito de uma implementação padrão derivada automaticamente. Se você usar #[derive(Default)]em uma estrutura de dados, o compilador criará automaticamente uma função padrão para você que preenche cada campo com seu valor padrão. O valor booleano padrão é falso, o valor integral padrão é 0.

O valor padrão de um inteiro sendo 0 é um problema aqui, pois você deseja que os campos inteiros sejam -1 por padrão. Você pode definir um novo tipo que implemente um valor padrão de -1 e usar isso em vez de i64em sua estrutura. (Eu não testei isso, mas deve funcionar).

No entanto, sugiro alterar ligeiramente sua estrutura de dados e usar em Option<i64>vez de i64. Não sei o contexto do seu código, mas parece que você está usando o valor especial -1 para representar o significado especial "infinito" ou "não há máximo". Em Rust, usamos um Optionpara representar um valor presente opcional. Não há necessidade de um hack -1. Uma opção pode ser Noneou Some(x)onde x seria o seu i64aqui. Pode até ser um inteiro sem sinal se -1 for o único valor negativo. O Optionvalor padrão é None, portanto, com as alterações propostas, seu código poderia ser assim:

#[derive(Default)]
struct cParams {
    iInsertMax: Option<u64>,
    iUpdateMax: Option<u64>,
    iDeleteMax: Option<u64>,
    iInstanceMax: Option<u64>,
    tFirstInstance: bool,
    tCreateTables: bool,
    tContinue: bool,
}

let p = cParams { iInsertMax: Some(10), ..Default::default() };
Zargony
fonte
1
Obrigado, fiz uma leitura rápida, mas vou reler para entender melhor. Os padrões "naturais" que algumas linguagens usam, como eu acredito que zero, falso, "", etc., são adequados para mim. Eu entendo que há implicações mais amplas do que meu pequeno "problema" para resolver. Capacidade de indicar, por exemplo. "iVal: i64 = 0" resolveria minhas necessidades mais amplas, mas acho que isso não vai acontecer. O "# [derivando (padrão)]" deve resolver a maioria dos meus desejos. Não sei por que usei -1 em meu programa de teste, mas não é necessário (histórico). Seria muito útil (IMHO) poder atribuir um valor in situ onde o campo está definido.
Brian Oh
9
@BrianOh, tangencialmente, os "valores padrão para campos de estrutura" (ou seja, algo como struct Foo { val: i64 = 0 }) foram propostos e podem aparecer em versões posteriores.
manhã de
Seria bom se isso fosse implementado IMO - "struct foo {....". Fiz as alterações sugeridas por você, usando a estrutura conforme escrito na minha pergunta e com o padrão. Isso certamente me cai melhor e é muito mais conciso. Por não estar familiarizado com a sintaxe, um pequeno problema que eu tinha era não saber a sintaxe para TODOS os padrões. IE: Eu usei "= cParams {iInsertMax: 10, ..Default :: default ()};", mas na verdade eu quero que "iInstanceMax" também seja um padrão. IMO seria preferível que "# [derivando (Padrão)]" fizesse parte da estrutura, mas acho que a alternativa se adequa melhor ao compilador.
Brian Oh
2
Muito obrigado por isso. IMHO os padrões devem ser o padrão. IE. Eu não acho que deveria ser necessário especificar Default: default etc., etc. Eu também acho que os campos deveriam poder receber um valor onde eles são definidos. Isso é apenas da minha perspectiva simples, e eu percebo que o Rust foi projetado para ser seguro e que existe uma perspectiva muito mais ampla do que a minha. Quando alguém está aprendendo o idioma (ou pelo menos eu), a implementação atual parece um pouco complicada. Rust não é uma linguagem simples, IMHO, e quanto mais isso puder ser feito para simplificá-lo, melhor para mim, pelo menos.
Brian Oh
2
É necessário definir padrões para todos os campos ao implementar Defaultpara uma estrutura?
Matthew Stevenson