Typy wbudowane
Zero daje ci mały, regularny zestaw typów prostych. Nic egzotycznego, nic zaskakującego: tylko te, których potrzebuje każdy język systemowy, nazwane w spójny sposób.
| Rodzina | Typy | Uwagi |
|---|---|---|
| Liczby całkowite ze znakiem | i8, i16, i32, i64 | Kod uzupełnień do dwóch. |
| Liczby całkowite bez znaku | u8, u16, u32, u64 | Tylko 0 i wartości dodatnie. |
| Rozmiar wskaźnika | usize, isize | Szerokość zgodna ze wskaźnikiem platformy. |
| Liczby zmiennoprzecinkowe | f32, f64 | IEEE-754. |
| Wartość logiczna | bool | true lub false. |
| Znak | char | Pojedyncza wartość skalarna Unicode. |
| Tekst | String | Tekst w UTF-8. |
| Pusty | Void | "Brak użytecznej wartości". |
To pełna lista typów prostych, z których korzystasz na co dzień. Typy złożone (shape, enum, choice) buduje się z nich.
Liczby całkowite
Typy całkowite mają jednolity schemat nazw: i dla typów ze znakiem, u dla typów bez znaku, a potem liczba bitów. i32 to 32-bitowa liczba całkowita ze znakiem, u8 to bajt bez znaku, a i64 to 64-bitowa liczba całkowita ze znakiem.
let small_signed: i8 = -120
let byte: u8 = 250
let id: i32 = 1
let big: i64 = 9_000_000_000
let index: usize = 0
Domyślnym typem literału bez sufiksu jest i32, chyba że otaczający kontekst wymusza coś innego:
let answer = 42 // i32
Gdy potrzebujesz konkretnej szerokości, dodaj sufiks do literału albo adnotację do wiązania:
let byte = 250_u8 // literał z typem
let byte: u8 = 250 // wiązanie z typem
Obie formy dają tę samą wartość. Forma z sufiksem literału przydaje się, gdy przekazujesz literał bezpośrednio do funkcji albo budujesz strukturę:
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
Jaką szerokość wybrać
Krótka reguła:
i32do większości obliczeń ze znakiem. Wystarczająco szeroki dla niemal wszystkiego, co liczysz, i szybki na każdej platformie.u8do pracy na bajtach. Bajty z pliku, bajty w buforze, bajty przesyłane siecią.u32/u64do nieujemnych liczników, gdy liczy się zakres. Przesunięcia w plikach powyżej 2 GB, duże liczniki.usizedo rozmiarów i indeksów. Ma rozmiar wskaźnika, czyli odpowiada temu, czego platforma używa do adresowania pamięci.i64do czasu od epoki i podobnych wartości. Wystarczy na nanosekundy przez setki lat.
Wybór najmniejszego pasującego typu to dobra praktyka; wybór za małego typu i przepełnienie to znacznie większy problem niż typ o jeden bit za szeroki.
Wartości logiczne
let ok = true
let done: bool = false
bool ma dokładnie dwie wartości: true i false. To literały, a nie stałe importowane skądś. Warunek w if lub while jest typu bool: liczby całkowite ani teksty nie mają niejawnej wartości logicznej.
if ok {
check world.out.write("tak\n")
} else {
check world.out.write("nie\n")
}
Instrukcje warunkowe szczegółowo omawia artykuł If/else.
Liczby zmiennoprzecinkowe
f32 i f64 to odpowiednio 32-bitowe i 64-bitowe liczby zmiennoprzecinkowe IEEE-754. Używaj ich, gdy potrzebujesz wartości ułamkowych: pomiarów, proporcji, geometrii. Do dokładnych obliczeń na kwotach pieniędzy lepiej użyć liczb całkowitych w najmniejszej jednostce (grosze, satoshi) niż liczb zmiennoprzecinkowych.
let ratio: f32 = 0.5
let pi: f64 = 3.141592653589793
f64 to domyślny typ literałów zmiennoprzecinkowych bez sufiksu.
Znaki i teksty
char przechowuje pojedynczą wartość skalarną Unicode:
let initial: char = 'Z'
String to ciąg znaków, który biblioteka standardowa zwykle koduje w UTF-8. Literały tekstowe używają podwójnych cudzysłowów:
let message: String = "cześć z zero\n"
Działają typowe sekwencje ucieczki: \n dla nowej linii, \t dla tabulatora, \\ dla dosłownego ukośnika wstecznego, \" dla dosłownego cudzysłowu.
let multi_line = "linia pierwsza\nlinia druga\n"
Biblioteka standardowa udostępnia bajtowe widoki tekstu do pracy niskopoziomowej. Forma std.mem.span("zero") zwraca Span<u8> na bajtach, co przydaje się przy parsowaniu, haszowaniu albo porównywaniu bajt po bajcie.
Void
Void to typ Zero oznaczający "brak użytecznej wartości zwracanej". Używają go funkcje istniejące dla swoich efektów ubocznych:
pub fun main(world: World) -> Void raises {
check world.out.write("cześć\n")
}
main coś wypisuje i kończy działanie. Nie ma wartości do oddania, więc typem jest Void. Zobaczysz Void przy większości funkcji korzystających z World: wybiera się je dla ich efektu, a nie wyniku.
Podkreślniki w literałach liczbowych
Długie literały liczbowe mogą używać podkreślników jako separatorów wizualnych. Kompilator je ignoruje, więc służą wyłącznie czytelności:
let big = 9_000_000_000_i64
let bytes = 1_048_576_u32 // 1 MiB
Wstawiaj je wszędzie tam, gdzie cyfry zaczynają być trudne do policzenia.
Ściąga: sufiksy literałów z typem
| Sufiks | Typ | Przykład |
|---|---|---|
_i8 / _i16 / _i32 / _i64 | Liczba całkowita ze znakiem | 127_i8 |
_u8 / _u16 / _u32 / _u64 | Liczba całkowita bez znaku | 255_u8 |
_usize / _isize | Rozmiar wskaźnika | 0_usize |
_f32 / _f64 | Liczba zmiennoprzecinkowa | 0.5_f32 |
Sięgaj po nie, gdy tworzysz wartość, a otaczający kontekst nie ustala jej typu.
Dalej: funkcje
Typy proste są bezużyteczne, jeśli nie ma co z nimi robić. Następny artykuł omawia funkcje w Zero: jak je deklarować, zwracać z nich wartości i łączyć je w prawdziwe programy.
Najczęściej zadawane pytania
Jakie typy proste ma Zero?
Zero ma liczby całkowite ze znakiem o określonym rozmiarze i8, i16, i32, i64; liczby bez znaku u8, u16, u32, u64; liczby o rozmiarze wskaźnika usize i isize; liczby zmiennoprzecinkowe f32 i f64; bool; char; String; oraz Void dla funkcji, które nie zwracają nic użytecznego.
Jaki jest domyślny typ liczby całkowitej w Zero?
Literał całkowity bez sufiksu, taki jak 42, ma domyślnie typ i32, chyba że kontekst wymusza inny. Aby użyć konkretnej szerokości, zapisz literał z sufiksem, np. 42_u8 lub 42_i64, albo jawnie podaj typ wiązania: let count: u8 = 42.
Czy Zero ma osobny typ tekstowy?
Tak. Literały tekstowe, takie jak "hello", mają wbudowany typ tekstowy, który biblioteka standardowa traktuje jako ciąg bajtów (zwykle UTF-8). Do pracy na niższym poziomie z bajtami biblioteka standardowa udostępnia spany i narzędzia bajtowe; do operacji na znakach służy char dla pojedynczych wartości skalarnych.
Co oznacza Void w Zero?
Void to typ zwracany funkcji, która nie daje użytecznej wartości: istnieje tylko dla swoich efektów ubocznych. Zwyczajowa sygnatura pub fun main(world: World) -> Void raises używa Void, bo main ma wykonać I/O i zakończyć działanie, a nie zwrócić wartość.
Czym różni się i32 od u32 w Zero?
i32 to 32-bitowa liczba całkowita ze znakiem o zakresie od −2 147 483 648 do 2 147 483 647. u32 jest bez znaku i ma zakres od 0 do 4 294 967 295. Używaj typów ze znakiem, gdy wartości ujemne mają sens, a bez znaku, gdy wartość ujemna byłaby błędem: dla liczników, indeksów, rozmiarów i tak dalej.