Czy istnieje szybszy / krótszy sposób inicjalizacji zmiennych w strukturze Rusta?

102

W poniższym przykładzie wolałbym przypisać wartość do każdego pola w strukturze w deklaracji pól. Alternatywnie, aby przypisać wartość do pól, potrzeba jednej dodatkowej instrukcji dla każdego pola. Wszystko, co chcę zrobić, to przypisać wartości domyślne podczas tworzenia wystąpienia struktury.

Czy jest na to bardziej zwięzły sposób?

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
źródło

Odpowiedzi:

162

Możesz podać wartości domyślne dla swojej struktury, implementując Defaultcechę. defaultFunkcja będzie wyglądać aktualnej newfunkcji:

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

Następnie możesz utworzyć wystąpienie struktury, podając tylko wartości inne niż domyślne:

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

Po wprowadzeniu niewielkich zmian w strukturze danych można skorzystać z domyślnej implementacji wyprowadzonej automatycznie. Jeśli używasz #[derive(Default)]struktury danych, kompilator automatycznie utworzy domyślną funkcję, która wypełni każde pole wartością domyślną. Domyślna wartość logiczna to fałsz, a domyślna wartość całkowita to 0.

Domyślna wartość liczby całkowitej wynosząca 0 jest tutaj problemem, ponieważ chcesz, aby pola liczb całkowitych miały domyślnie wartość -1. Możesz zdefiniować nowy typ, który implementuje domyślną wartość -1 i użyć tego zamiast i64w swojej strukturze. (Nie testowałem tego, ale powinno działać).

Sugerowałbym jednak nieznaczną zmianę struktury danych i użycie Option<i64>zamiast i64. Nie znam kontekstu Twojego kodu, ale wygląda na to, że używasz specjalnej wartości -1 do reprezentowania specjalnego znaczenia „nieskończony” lub „nie ma maksimum”. W Rust używamy znaku an Optiondo reprezentowania opcjonalnej wartości bieżącej. Nie ma potrzeby hakowania -1. Opcją może być albo Nonealbo Some(x)gdzie x będzie i64tutaj twoje . Może to być nawet liczba całkowita bez znaku, jeśli -1 była jedyną wartością ujemną. Wartość domyślna Optionto None, więc przy proponowanych zmianach Twój kod mógłby wyglądać następująco:

#[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
źródło
1
Dzięki, przeczytałem szybko, ale przeczytam ponownie, aby lepiej zrozumieć. „Naturalne” wartości domyślne, których używają niektóre języki, takie jak Wierzę, że zero, fałsz, „” itd., Będą mi odpowiadały. Rozumiem, że istnieją szersze implikacje niż mój mały „problem” do rozwiązania. Możliwość podania np. „iVal: i64 = 0” rozwiązałoby moje szersze potrzeby, ale myślę, że tak się nie stanie. „# [Pochodzenie (domyślne)]” powinno rozwiązać większość moich potrzeb. Nie jestem pewien, dlaczego użyłem -1 w moim programie testowym, ale nie jest to potrzebne (historyczne). Byłoby bardzo przydatne (IMHO), aby móc przypisać wartość in situ, gdy pole jest zdefiniowane.
Brian Oh,
9
@BrianOh, tangencjalnie, zaproponowano "domyślne wartości dla pól struktur" (tj. Coś podobnego struct Foo { val: i64 = 0 }) i mogą pojawić się w późniejszych wersjach.
huon
Byłoby dobrze, gdyby zostały zaimplementowane IMO - "struct foo {....". Wprowadziłem zmiany zgodnie z sugestią przez Ciebie, używając struktury, która została napisana w moim pytaniu i z ustawieniem domyślnym. To z pewnością bardziej mi odpowiada i jest o wiele bardziej zwięzłe. Ponieważ nie byłem zaznajomiony ze składnią, jednym drobnym problemem, który miałem, był brak znajomości składni WSZYSTKICH ustawień domyślnych. IE: Użyłem "= cParams {iInsertMax: 10, ..Default :: default ()};", ale tak naprawdę chcę, aby "iInstanceMax" również było wartością domyślną. IMO byłoby lepiej, aby „# [pochodzenie (domyślne)]” było częścią struktury, ale wydaje mi się, że alternatywa lepiej pasuje do kompilatora.
Brian Oh,
2
Wielkie dzięki za to. IMHO domyślne powinny być domyślne. TO ZNACZY. Uważam, że nie powinno być konieczne określanie wartości Default: default itp., Itd. Uważam również, że polom należy przypisać wartość tam, gdzie są zdefiniowane. To tylko z mojej prostej perspektywy i zdaję sobie sprawę, że Rust został zaprojektowany tak, aby był bezpieczny i że istnieje znacznie szersza perspektywa niż moja. Kiedy ktoś uczy się języka (a przynajmniej ja), obecna implementacja wydaje się trochę uciążliwa. Rust nie jest prostym językiem IMHO i im więcej można zrobić, aby go uprościć, tym lepiej dla mnie.
Brian Oh
2
Czy konieczne jest zdefiniowanie wartości domyślnych dla wszystkich pól podczas implementacji Defaultdla struktury?
Matthew Stevenson,