Protokol Vyrovnávací paměti Základy: Dart

Tento návod poskytuje základní Dart programátor je úvod k práci s vyrovnávací paměti protokolu, pomocí proto3 verze z vyrovnávací paměti protokolu jazyk. Procházením vytvořením jednoduchého příkladu aplikace vám ukáže, jak

  • definovat formáty zpráv v souboru .proto.
  • použijte kompilátor vyrovnávací paměti protokolu.
  • pro zápis a čtení zpráv Použijte rozhraní Dart protocol buffer API.

Toto není komplexní návod k použití vyrovnávací paměti protokolu v Dart . Podrobnější referenční informace naleznete v příručce jazyka vyrovnávací paměti protokolu, v jazykové prohlídce Dart, v odkazu Dart API, v Průvodci kódem generovaném Dart a v odkazu na kódování.

Proč používat vyrovnávací paměti protokolu?

příklad, který použijeme, je velmi jednoduchá aplikace „adresář“, která umí číst a psát kontaktní údaje lidí do a ze souboru. Každá osoba v adresáři má jméno, ID, e-mailovou adresu a kontaktní telefonní číslo.

Jak serializujete a načítáte takto strukturovaná data? Existuje několik způsobů, jak tento problém vyřešit:

  • můžete vymýšlet ad-hoc způsob, jak kódovat data položky do jednoho řetězce – jako je kódování 4 ints jako „12:3:-23:67“. Jedná se o jednoduchý a flexibilní přístup, i když to vyžaduje psaní jednorázového kódování a parsování kódu, a parsování ukládá malé náklady na běh. To funguje nejlépe pro kódování velmi jednoduchých dat.
  • Serializujte data do XML. Tento přístup může být velmi atraktivní, protože XML je (tak nějak) čitelný pro člověka a existují závazné knihovny pro mnoho jazyků. To může být dobrá volba, pokud chcete sdílet data s jinými aplikacemi/projekty. XML je však notoricky náročný na prostor a kódování/dekódování může aplikacím uložit obrovský výkon. Také navigace ve stromu Dom XML je podstatně složitější, než by navigace v jednoduchých polích ve třídě normálně byla.

protokolové vyrovnávací paměti jsou flexibilní, efektivní a automatizované řešení, které přesně řeší tento problém. Pomocí vyrovnávací paměti protokolu napíšete .proto popis datové struktury, kterou chcete uložit. Z toho, kompilátor vyrovnávací paměti protokolu vytvoří třídu, která implementuje automatické kódování a analýzu dat vyrovnávací paměti protokolu s efektivním binárním formátem. Generovaná třída poskytuje gettery a settery pro pole, která tvoří vyrovnávací paměť protokolu, a stará se o podrobnosti čtení a zápisu vyrovnávací paměti protokolu jako jednotky. Důležité je, že protokol vyrovnávací paměť formát podporuje myšlenku prodloužení formátu v průběhu času tak, že kód může stále číst data zakódovaná starém formátu.

, Kde najít příklad kódu

Náš příklad je nastavit z příkazového lineapplications pro správu adresu bookdata souboru, kódované pomocí vyrovnávací paměti protokolu.Příkaz dart add_person.dart přidá nový záznam do datového souboru. Příkaz dart list_people.dart analyzuje datový soubora vytiskne data do konzoly.

kompletní příklad najdete v adresáři příkladů repozitáře GitHub.

definování formátu protokolu

Chcete-li vytvořit aplikaci adresáře, musíte začít s.proto soubor. Definice je v .proto soubor aresimple: můžete přidat zprávu pro každou datovou strukturu, kterou chcete toserialize, pak zadejte název a typ pro každé pole ve zprávě. V našem příkladu je .proto soubor, který definuje zprávy,addressbook.proto.

soubor .proto začíná deklarací balíčku, která pomáhá předcházet konfliktům pojmenování mezi různými projekty.

syntax = "proto3";package tutorial;import "google/protobuf/timestamp.proto";

dále máte definice zpráv. Zpráva je pouze agregátobsahující sadu zadaných polí. Mnoho standardní jednoduché datové typy areavailable jako studijní typy, včetně boolint32floatdoublestring. Můžete také přidat další strukturu zpráv pomocí jiných typů zpráv jako polní typy.

message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5;}// Our address book file is just one of these.message AddressBook { repeated Person people = 1;}

Ve výše uvedeném příkladu, Person zpráva obsahujePhoneNumber zprávy, zatímco AddressBook messagecontains Person zprávy. Můžete dokonce definovat typy zpráv uvnitř jiných zpráv – jak vidíte, typPhoneNumber je definován uvnitř Person. Můžetetaké definovat enum typy, pokud chcete jeden z vašich polí mají jeden předem definovaný seznam hodnot – zde můžete zadat, že telefonní číslo může být jeden z MOBILEHOME neboWORK.

značky „= 1“, „= 2 „na každém prvku identifikují jedinečnou „značku“, kterou pole používá v binárním kódování. Tag čísla 1-15 vyžadovat jeden méně byte kódování, než vyšší čísla, tak optimalizace se můžete rozhodnout používat tyto značky pro běžně používané nebo opakované prvky, takže kategorie 16 a vyšší pro méně běžně používané volitelné prvky. Každý prvek v opakovaném poli vyžaduje překódování čísla značky, takže opakovaná pole jsou zvláště dobrými kandidáty pro tuto optimalizaci.

Pokud není nastavena hodnota pole, použije se hodnota adefault: zerofor numerické typy, prázdný řetězec pro řetězce, false pro bools. Pro embeddedmessages je výchozí hodnota vždy „výchozí instance“ nebo „prototyp“ zprávy, která nemá nastavené žádné pole. Volání accessoru pro získání hodnoty pole, které nebylo explicitně nastaveno, vždy vrátí hodnotu default tohoto pole.

Pokud je pole repeated, může být pole opakováno kolikrát (včetně nuly). Pořadí opakovaných hodnot bude zachováno ve vyrovnávací paměti protokolu. Přemýšlejte o opakovaných polích jako o dynamicky velkých polích.

kompletní průvodce zápisem souborů .proto – včetně všech možných typů polí-najdete v Průvodci jazykem vyrovnávací paměti protokolu. Nehledejte zařízení podobná dědičnosti třídy, ačkoli-vyrovnávací paměti protokolu to nedělají.

Kompilace své vyrovnávací paměti protokolu

Nyní, když máte .proto další věc, kterou musíte udělat, je vytvořit třídy, které budete potřebovat pro čtení a zápis AddressBook (a tedy PersonPhoneNumber) zprávy. K tomu budete muset spustit kompilátor vyrovnávací paměti protokolu protoc.proto:

  1. Pokud nemáte nainstalován kompilátor, stáhnout balíček a postupujte podle pokynů v souboru README.
  2. nainstalujte plugin vyrovnávací paměti protokolu Dart, jak je popsáno v jeho README. Spustitelný bin/protoc-gen-dart musí být v PATH protokol vyrovnávací paměti protoc najít.
  3. Nyní spustit kompilátor, určující zdrojový adresář (kde se vaše aplikace je zdrojový kód životy – aktuální adresář se používá, pokud nechcete poskytnout hodnotu), cílový adresář (kam chcete vygenerovaný kód jít; často stejné jako $SRC_DIR), a cesta k .proto. V tomto případě vyvoláte:
    protoc -I=$SRC_DIR --dart_out=$DST_DIR $SRC_DIR/addressbook.proto

    protože chcete kód Dart, použijete volbu --dart_out – podobné možnosti jsou k dispozici pro jiné podporované jazyky.

tím se vygeneruje addressbook.pb.dart ve vašem určeném cílovém adresáři.

Vyrovnávací paměti Protokolu API

Generování addressbook.pb.dart vám dává následující užitečné typy:

  • AddressBook class List<Person> get people getter.
  • Person třídy s accessor metod pro nameidemailphones.
  • Person_PhoneNumber třídy, s accessor metod pro numbertype.
  • a Person_PhoneType třída se statickými poli pro každou hodnotu vPerson.PhoneType enum.

můžete si přečíst více o podrobnostech přesně to, co je generováno v Dart generovaný kód průvodce.

psaní zprávy

nyní zkusme použít třídy vyrovnávací paměti protokolu. První věc, kterou chcete, aby aplikace adresáře mohla udělat, je napsat osobní údaje do souboru adresáře. Chcete-li to provést, musíte vytvořit a naplnit instance tříd vyrovnávací paměti protokolu a poté je zapsat do výstupního proudu.

Tady je program, který čte AddressBook ze souboru, přidá jeden nový Person je to založené na vstup uživatele, a píše the new AddressBook do souboru znovu. Jsou zvýrazněny části, které přímo volají nebo referenční kód generovaný kompilátorem protokolu.

import 'dart:io';import 'dart_tutorial/addressbook.pb.dart';// This function fills in a Person message based on user input.Person promtForAddress() { Person person = Person(); print('Enter person ID: '); String input = stdin.readLineSync(); person.id = int.parse(input); print('Enter name'); person.name = stdin.readLineSync(); print('Enter email address (blank for none) : '); String email = stdin.readLineSync(); if (email.isNotEmpty) { person.email = email; } while (true) { print('Enter a phone number (or leave blank to finish): '); String number = stdin.readLineSync(); if (number.isEmpty) break; Person_PhoneNumber phoneNumber = Person_PhoneNumber(); phoneNumber.number = number; print('Is this a mobile, home, or work phone? '); String type = stdin.readLineSync(); switch (type) { case 'mobile': phoneNumber.type = Person_PhoneType.MOBILE; break; case 'home': phoneNumber.type = Person_PhoneType.HOME; break; case 'work': phoneNumber.type = Person_PhoneType.WORK; break; default: print('Unknown phone type. Using default.'); } person.phones.add(phoneNumber); } return person;}// Reads the entire address book from a file, adds one person based// on user input, then writes it back out to the same file.main(List arguments) { if (arguments.length != 1) { print('Usage: add_person ADDRESS_BOOK_FILE'); exit(-1); } File file = File(arguments.first); AddressBook addressBook; if (!file.existsSync()) { print('File not found. Creating new file.'); addressBook = AddressBook(); } else { addressBook = AddressBook.fromBuffer(file.readAsBytesSync()); } addressBook.people.add(promtForAddress()); file.writeAsBytes(addressBook.writeToBuffer());}

Čtení Zprávy

samozřejmě, adresář by neměl být moc použít, pokud jste nemohli získat žádné informace! Tento příklad přečte soubor vytvořený výše uvedeným příkladem a vytiskne všechny informace v něm.

import 'dart:io';import 'dart_tutorial/addressbook.pb.dart';import 'dart_tutorial/addressbook.pbenum.dart';// Iterates though all people in the AddressBook and prints info about them.void printAddressBook(AddressBook addressBook) { for (Person person in addressBook.people) { print('Person ID: ${ person.id}'); print(' Name: ${ person.name}'); if (person.hasEmail()) { print(' E-mail address:${ person.email}'); } for (Person_PhoneNumber phoneNumber in person.phones) { switch (phoneNumber.type) { case Person_PhoneType.MOBILE: print(' Mobile phone #: '); break; case Person_PhoneType.HOME: print(' Home phone #: '); break; case Person_PhoneType.WORK: print(' Work phone #: '); break; default: print(' Unknown phone #: '); break; } print(phoneNumber.number); } }}// Reads the entire address book from a file and prints all// the information inside.main(List arguments) { if (arguments.length != 1) { print('Usage: list_person ADDRESS_BOOK_FILE'); exit(-1); } // Read the existing address book. File file = new File(arguments.first); AddressBook addressBook = new AddressBook.fromBuffer(file.readAsBytesSync()); printAddressBook(addressBook);}

Rozšíření Protokolu Vyrovnávací paměti

Dříve nebo později po uvolnění kódu, který používá protokol vyrovnávací paměti,budete nepochybně chtít „vylepšit“ vyrovnávací paměti protokolu je definice. Pokud chcete, aby vaše nové vyrovnávací paměti byly zpětně kompatibilní – a vaše staré vyrovnávací paměti byly dopředu kompatibilní-a téměř jistě to chcete-pak existují některá pravidla, která musíte dodržovat. V nové verzi vyrovnávací paměti theprotocol:

  • nesmíte měnit čísla značek všech existujících polí.
  • pole můžete smazat.
  • můžete přidat nová pole, ale musíte použít nová čísla značek (tj. čísla značek, která nebyla nikdy použita v této vyrovnávací paměti protokolu, dokonce ani odstraněná pole).

(existujíněkteré výjimkytyto pravidla, ale jsou zřídka používány.)

Pokud budete postupovat podle těchto pravidel, starý kód bude šťastně číst nové zprávy aprostě ignorovat všechna nová pole. Ke starému kódu budou mít singulární pole, která bylaodstranit, jednoduše výchozí hodnotu a odstraněná opakovaná pole budou prázdná. Nový kód bude také transparentně číst staré zprávy.

Mějte však na paměti, že nová pole nebudou ve starých zprávách přítomna,takže budete muset udělat něco rozumného s výchozí hodnotou. Atype-specificdefault valueis used: pro řetězce je výchozí hodnotou prázdný řetězec. Pro booleans je hodnota default nepravdivá. Pro číselné typy je výchozí hodnota nula.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.