Existe-t-il un moyen plus rapide / plus court d'initialiser des variables dans une structure Rust?

102

Dans l'exemple suivant, je préférerais de loin attribuer une valeur à chaque champ de la structure dans la déclaration des champs. Sinon, il faut en fait une instruction supplémentaire pour chaque champ pour attribuer une valeur aux champs. Tout ce que je veux être en mesure de faire est d'assigner des valeurs par défaut lorsque la structure est instanciée.

Existe-t-il une manière plus succincte de procéder?

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
la source

Réponses:

162

Vous pouvez fournir des valeurs par défaut pour votre structure en implémentant le Defaulttrait. La defaultfonction ressemblerait à votre newfonction actuelle :

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

Vous pouvez ensuite instancier la structure en ne donnant que les valeurs non par défaut:

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

Avec quelques modifications mineures de votre structure de données, vous pouvez tirer parti d'une implémentation par défaut dérivée automatiquement. Si vous utilisez #[derive(Default)]sur une structure de données, le compilateur créera automatiquement une fonction par défaut pour vous qui remplit chaque champ avec sa valeur par défaut. La valeur booléenne par défaut est false, la valeur intégrale par défaut est 0.

La valeur par défaut d'un entier étant 0 est un problème ici car vous voulez que les champs entiers soient -1 par défaut. Vous pouvez définir un nouveau type qui implémente une valeur par défaut de -1 et l'utiliser au lieu de i64dans votre structure. (Je n'ai pas testé cela, mais cela devrait fonctionner).

Cependant, je suggère de modifier légèrement votre structure de données et d'utiliser à la Option<i64>place de i64. Je ne connais pas le contexte de votre code, mais il semble que vous utilisiez la valeur spéciale de -1 pour représenter la signification spéciale "infini" ou "il n'y a pas de max". Dans Rust, nous utilisons un Optionpour représenter une valeur actuelle facultative. Il n'y a pas besoin d'un hack -1. Une option peut être soit Noneou Some(x)où x serait votre i64ici. Il peut même s'agir d'un entier non signé si -1 était la seule valeur négative. La Optionvaleur par défaut est None, donc avec les modifications proposées, votre code pourrait ressembler à ceci:

#[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
la source
1
Merci, j'ai eu une lecture rapide, mais je vais relire pour mieux comprendre. Les valeurs par défaut «naturelles» que certaines langues utilisent, comme je crois zéro, faux, «», etc., me conviendraient. Je comprends qu'il y a des implications plus larges que mon petit "problème" à résoudre. Capacité à énoncer par exemple. "iVal: i64 = 0", résoudrait mes besoins plus larges, mais je suppose que cela ne se produira pas. Le "# [dérivant (par défaut)]" devrait résoudre la plupart de mes besoins. Je ne sais pas pourquoi j'ai utilisé -1 dans mon programme de test, mais ce n'est pas nécessaire (historique). Il serait très utile (IMHO) de pouvoir attribuer une valeur in situ là où le champ est défini.
Brian Oh
9
@BrianOh, tangentiellement, les "valeurs par défaut pour les champs de structure" (c'est-à-dire quelque chose comme struct Foo { val: i64 = 0 }) ont été proposées et peuvent donc apparaître dans les versions ultérieures.
huon
Ce serait bien si cela était mis en œuvre IMO - "struct foo {....". J'ai apporté les modifications suggérées par vous, en utilisant la structure telle qu'écrite dans ma question et avec la valeur par défaut. Cela me convient certainement mieux et est beaucoup plus concis. N'étant pas familier avec la syntaxe, un problème mineur que j'ai eu était de ne pas connaître la syntaxe de TOUS les paramètres par défaut. IE: J'ai utilisé "= cParams {iInsertMax: 10, ..Default :: default ()};", mais je veux en fait que "iInstanceMax" soit également une valeur par défaut. IMO, il serait préférable que "# [deriving (Default)]" fasse partie de la structure, mais je suppose que l'alternative convient mieux au compilateur.
Brian Oh
2
Merci beaucoup pour cela. IMHO les valeurs par défaut doivent être la valeur par défaut. C'EST À DIRE. Je ne pense pas qu'il soit nécessaire de spécifier Default: default etc., etc. Je pense aussi que les champs devraient pouvoir se voir attribuer une valeur là où ils sont définis. C'est juste de mon point de vue simple, et je me rends compte que Rust est conçu pour être sûr et qu'il y a une perspective beaucoup plus large que la mienne. Quand on apprend la langue (ou du moins moi), l'implémentation actuelle semble un peu lourde. Rust n'est pas un langage simple à mon humble avis, et plus ce qui peut être fait pour le simplifier, mieux c'est pour moi au moins.
Brian Oh
2
Est-il nécessaire de définir les valeurs par défaut pour tous les champs lors de l'implémentation Defaultd'une structure?
Matthew Stevenson