¿Existe una forma más rápida / corta de inicializar variables en una estructura de Rust?

102

En el siguiente ejemplo, preferiría asignar un valor a cada campo en la estructura en la declaración de los campos. Alternativamente, se necesita efectivamente una declaración adicional para cada campo para asignar un valor a los campos. Todo lo que quiero poder hacer es asignar valores predeterminados cuando se crea una instancia de la estructura.

¿Existe una forma más sucinta de hacer esto?

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
fuente

Respuestas:

161

Puede proporcionar valores predeterminados para su estructura implementando el Defaultrasgo. La defaultfunción se vería como su newfunción actual :

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

Luego puede instanciar la estructura dando solo los valores no predeterminados:

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

Con algunos cambios menores en su estructura de datos, puede aprovechar una implementación predeterminada derivada automáticamente. Si lo usa #[derive(Default)]en una estructura de datos, el compilador creará automáticamente una función predeterminada para usted que llena cada campo con su valor predeterminado. El valor booleano predeterminado es falso, el valor integral predeterminado es 0.

El valor predeterminado de un entero que es 0 es un problema aquí, ya que desea que los campos de enteros sean -1 por defecto. Puede definir un nuevo tipo que implemente un valor predeterminado de -1 y usarlo en lugar de i64en su estructura. (No lo he probado, pero debería funcionar).

Sin embargo, sugeriría cambiar ligeramente la estructura de datos y usar en Option<i64>lugar de i64. No conozco el contexto de su código, pero parece que está usando el valor especial de -1 para representar el significado especial "infinito", o "no hay máximo". En Rust, usamos an Optionpara representar un valor presente opcionalmente. No es necesario un truco -1. Una opción puede ser Noneo Some(x)donde x sería tu i64aquí. Incluso podría ser un entero sin signo si -1 fuera el único valor negativo. El Optionvalor predeterminado es None, por lo que con los cambios propuestos, su código podría verse así:

#[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
fuente
1
Gracias, tuve una lectura rápida, pero volveré a leer para comprender mejor. Los valores predeterminados "naturales" que utilizan algunos idiomas, como creo que cero, falso, "", etc., me vendrían bien. Entiendo que hay implicaciones más amplias que mi pequeño "problema" que resolver. Capacidad para indicar, por ejemplo. "iVal: i64 = 0", resolvería mis necesidades más amplias, pero supongo que eso no sucederá. El "# [derivado (predeterminado)]" debería resolver la mayoría de mis necesidades. No estoy seguro de por qué usé -1 en mi programa de prueba, pero no es necesario (histórico). Sería muy útil (en mi humilde opinión) poder asignar un valor in situ donde se define el campo.
Brian Oh
9
@BrianOh, tangencialmente, se han propuesto los "valores predeterminados para los campos de estructura" (es decir, algo así struct Foo { val: i64 = 0 }) y, por lo tanto, pueden aparecer en versiones posteriores.
huon
Sería bueno si eso se implementara IMO - "struct foo {....". Hice los cambios sugeridos por usted, usando la estructura como está escrita en mi pregunta y con el valor predeterminado. Eso ciertamente me queda mejor y es mucho más conciso. Al no estar familiarizado con la sintaxis, un problema menor que tuve fue no conocer la sintaxis de TODOS los valores predeterminados. IE: Usé "= cParams {iInsertMax: 10, ..Default :: default ()};", pero en realidad quiero que "iInstanceMax" también sea un valor predeterminado. En mi opinión, sería preferible que "# [derivando (predeterminado)]" fuera parte de la estructura, pero supongo que la alternativa se adapta mejor al compilador.
Brian Oh
2
Muchas gracias por eso. En mi humilde opinión, los valores predeterminados deberían ser los predeterminados. ES DECIR. No creo que sea necesario especificar Default: default, etc., etc. También creo que a los campos se les debería poder asignar un valor donde estén definidos. Eso es solo desde mi perspectiva simple, y me doy cuenta de que Rust está diseñado para ser seguro y que hay una perspectiva mucho más amplia que la mía. Cuando uno está aprendiendo el idioma (o al menos yo), la implementación actual parece un poco engorrosa. Rust no es un lenguaje simple en mi humilde opinión, y cuanto más se pueda hacer para simplificarlo, al menos mejor para mí.
Brian Oh
2
¿Es necesario definir valores predeterminados para todos los campos al implementar Defaultpara una estructura?
Matthew Stevenson