Szczegóły ebooka

Programowanie w języku Rust. Wydajność i bezpieczeństwo. Wydanie II

Programowanie w języku Rust. Wydajność i bezpieczeństwo. Wydanie II

Jim Blandy, Jason Orendorff, Leonora F. S. Tindall

Ebook

Twórcy aplikacji często zapominają o kodzie systemowym, a to dzięki niemu funkcjonują system operacyjny, sterowniki, system plików czy zarządzanie pamięcią. Żadna aplikacja nie będzie działać bez poprawnego kodu systemowego. Język Rust jest dla programistów systemowych wyjątkowym narzędziem, rozwiązującym wiele znanych od dziesięcioleci problemów. Pozwala uniknąć mnóstwa powszechnie popełnianych błędów i tworzyć należytej jakości kod systemowy.

Dzięki tej książce zaczniesz kodować w języku Rust. Zrozumiesz też istotę programowania systemowego. Dowiesz się, w jaki sposób zapewnić bezpieczeństwo pamięci i wątków, a także jak sprawić, aby program był wykonywany szybko i bez błędów. Nauczysz się bezpiecznego stosowania operacji współbieżnych i poznasz zasady obsługi błędów. Przekonasz się, w jaki sposób Rust umożliwia kontrolę nad zużyciem pamięci i procesora, dodatkowo otrzymasz mnóstwo wskazówek ułatwiających tworzenie wydajnego i bezpiecznego kodu. Przewodnik jest przeznaczony głównie dla programistów systemowych, na lekturze jednak skorzystają również twórcy aplikacji, którzy dowiedzą się, jak mogą pisać lepszy, efektywniejszy i łatwiejszy w utrzymaniu kod.

W książce między innymi:

  • solidne wprowadzenie do języka Rust
  • podstawowe typy danych, a także pojęcia związane z własnością i pożyczaniem
  • obsługa błędów, paczki i moduły
  • zestawy metod i typy generyczne
  • domknięcia, iteratory i programowanie asynchroniczne
  • zaawansowane mechanizmy języka Rust

Rust: zadbasz o najwyższą jakość oprogramowania systemowego!

Wstęp

Rozdział 1. Programiści systemowi mogą mieć fajne zabawki

  • Rust zdejmuje ciężar z naszych barków
  • Programowanie współbieżne zostaje ujarzmione
  • A na dodatek Rust wciąż jest szybki
  • Rust ułatwia współpracę

Rozdział 2. Pierwsze spotkanie z Rustem

  • rustup i Cargo
  • Funkcje w języku Rust
  • Pisanie i uruchamianie testów
  • Obsługa argumentów wiersza poleceń
  • Prosty serwer WWW
  • Programowanie współbieżne
    • Czym jest zbiór Mandelbrota?
    • Parsowanie argumentów wiersza poleceń
    • Odwzorowanie pikseli na liczby zespolone
    • Rysowanie zbioru
    • Zapis obrazu do pliku
    • Program Mandelbrota działający współbieżnie
    • Uruchomienie programu
    • Przezroczyste bezpieczeństwo
  • Narzędzia systemów plików i wiersza poleceń
    • Interfejs wiersza poleceń
    • Odczyt i zapis plików
    • Znajdowanie i zastępowanie

Rozdział 3. Typy proste

  • Typy numeryczne o ustalonej długości
    • Typy całkowite
    • Sprawdzane, przenoszące, nasycające i przepełniające operacje arytmetyczne
    • Typy zmiennoprzecinkowe
  • Typ logiczny
  • Typ znakowy
  • Krotki
  • Typy wskaźnikowe
    • Referencje
    • Pudełka
    • Wskaźniki niechronione
  • Tablice, wektory i podzbiory
    • Tablice
    • Wektory
    • Podzbiory
  • Typ String
    • Literały łańcuchowe
    • Łańcuchy bajtów
    • Łańcuchy znaków w pamięci
    • Typ String
    • Podstawowe cechy typu String
    • Inne typy znakowe
  • Nazwy zastępcze typów
  • Co dalej?

Rozdział 4. Reguła własności i przenoszenie własności

  • Reguła własności
  • Przenoszenie własności
    • Więcej operacji związanych z przeniesieniem własności
    • Przeniesienie własności a przepływ sterowania
    • Przeniesienie własności a struktury indeksowane
  • Typy kopiowalne - wyjątki od reguł przenoszenia własności
  • Rc i Arc: własność współdzielona

Rozdział 5. Referencje

  • Referencje do wartości
  • Stosowanie referencji
    • Referencje Rusta kontra referencje C++
    • Referencje a operacja przypisania
    • Referencje do referencji
    • Porównywanie referencji
    • Referencje nigdy nie są puste
    • Referencje do wyrażeń
    • Referencje do podzbiorów i zestawów metod
  • Bezpieczeństwo referencji
    • Referencja do zmiennej lokalnej
    • Przekazywanie referencji jako argumentów funkcji
    • Przekazywanie referencji do funkcji
    • Zwracanie referencji
    • Struktura zawierająca referencje
    • Odrębny cykl życia
    • Pomijanie parametrów cyklu życia
  • Referencje współdzielone kontra mutowalne
  • Walka ze sztormem na morzu obiektów

Rozdział 6. Wyrażenia

  • Język wyrażeń
  • Priorytety i łączność operatorów
  • Bloki kodu i średniki
  • Deklaracje
  • if i match
  • if let
  • Pętle
  • Sterowanie przepływem w pętlach
  • Wyrażenie return
  • Analiza przepływu sterowania
  • Wywołania funkcji i metod
  • Pola i elementy
  • Operatory referencji
  • Operatory arytmetyczne, bitowe, porównania i logiczne
  • Przypisanie
  • Rzutowanie typów
  • Domknięcia
  • Co dalej?

Rozdział 7. Obsługa błędów

  • Błąd panic
    • Odwinięcie stosu
    • Przerywanie procesu
  • Typ Result
    • Przechwytywanie błędów
    • Nazwy zastępcze typu Result
    • Wyświetlanie informacji o błędach
    • Propagacja błędów
    • Jednoczesna obsługa błędów różnych typów
    • Błędy, które nie powinny się zdarzyć
    • Ignorowanie błędów
    • Obsługa błędów w funkcji main()
    • Definiowanie własnego typu błędu
    • Co daje nam typ Result?

Rozdział 8. Paczki i moduły

  • Paczki
    • Edycje
    • Profile budowania
  • Moduły
    • Moduły zagnieżdżone
    • Umieszczanie modułów w oddzielnych plikach
    • Ścieżki i importy
    • Standardowe preludium
    • Publiczne deklaracje use
    • Publiczne pola struktur
    • Stałe i zmienne statyczne
  • Zmiana programu w bibliotekę
  • Katalog src/bin
  • Atrybuty
  • Testy i dokumentacja
    • Testy integracyjne
    • Dokumentacja
    • Doc-testy
  • Definiowanie zależności
    • Wersje
    • Cargo.lock
  • Publikowanie paczek na stronie crates.io
  • Obszary robocze
  • Więcej fajnych rzeczy

Rozdział 9. Struktury

  • Struktury z polami nazywanymi
  • Struktury z polami numerowanymi
  • Struktury puste
  • Reprezentacja struktur w pamięci
  • Definiowanie metod w bloku impl
    • Przekazywanie self z użyciem typów Box, Rc lub Arc
    • Funkcje powiązane z typami
  • Powiązane stałe
  • Struktury generyczne
  • Struktury z parametrem cyklu życia
  • Dziedziczenie standardowych zestawów metod
  • Zmienność wewnętrzna

Rozdział 10. Typy wyliczeniowe i wzorce

  • Typy wyliczeniowe
    • Typy wyliczeniowe zawierające dane
    • Typ wyliczeniowy w pamięci
    • Większe struktury danych stosujące typy wyliczeniowe
    • Generyczne typy wyliczeniowe
  • Wzorce
    • Literały, zmienne i symbole wieloznaczne
    • Wzorce w postaci krotki lub struktury
    • Wzorce typu tablica i fragment
    • Wzorce z referencjami
    • Strażniki wzorców
    • Dopasowanie do wielu wartości
    • Wzorce @
    • Gdzie używamy wzorców
    • Wypełnianie drzewa binarnego
  • Podsumowanie

Rozdział 11. Zestawy metod i typy generyczne

  • Stosowanie zestawów metod
    • Obiekt implementujący zestaw metod
    • Funkcje generyczne i parametry typów
    • Na co się zdecydować?
  • Definiowanie i implementacja zestawów metod
    • Metody domyślne
    • Implementacja zestawów metod dla istniejących już typów
    • Zestaw metod a słowo kluczowe Self
    • Rozszerzanie zestawu metod (dziedziczenie)
    • Funkcje powiązane z typami
  • W pełni kwalifikowana nazwa metody
  • Zestawy metod definiujące relacje między typami
    • Typy powiązane
    • Generyczny zestaw metod (czyli jak działa przeciążanie operatorów)
    • Impl Zestaw jako typ wyniku
    • Stałe powiązane
  • Inżynieria wsteczna ograniczeń
  • Zestawy metod u podstaw

Rozdział 12. Przeciążanie operatorów

  • Operatory arytmetyczne i bitowe
    • Operatory jednoargumentowe
    • Operatory dwuargumentowe
    • Operatory przypisania złożonego
  • Test równości
  • Porównania szeregujące
  • Interfejsy Index i IndexMut
  • Inne operatory

Rozdział 13. Interfejsy narzędziowe

  • Drop
  • Sized
  • Clone
  • Copy
  • Deref i DerefMut
  • Default
  • AsRef i AsMut
  • Borrow i BorrowMut
  • From i Into
  • TryFrom i TryInto
  • ToOwned
  • Borrow i ToOwned w działaniu

Rozdział 14. Domknięcia

  • Przechwytywanie zmiennych
    • Domknięcia, które pożyczają wartość
    • Domknięcia, które przejmują własność
  • Typy funkcji i domknięć
  • Domknięcia a wydajność
  • Domknięcia a bezpieczeństwo
    • Domknięcia, które zabijają
    • FnOnce
    • FnMut
    • Copy i Clone dla domknięć
  • Funkcje zwrotne
  • Skuteczne korzystanie z domknięć

Rozdział 15. Iteratory

  • Iterator i IntoIterator
  • Tworzenie iteratorów
    • Metody iter i iter_mut
    • Implementacje interfejsu IntoIterator
    • Funkcje from_fn i successors
    • Metody drain
    • Inne źródła iteratorów
  • Adaptery iteratorów
    • map i filter
    • filter_map i flat_map
    • flatten
    • take i take_while
    • skip i skip_while
    • peekable
    • fuse
    • Iteratory obustronne i rev
    • inspect
    • chain
    • enumerate
    • zip
    • by_ref
    • cloned i copied
    • cycle
  • Konsumowanie iteratorów
    • Proste agregaty: count, sum i product
    • max i min
    • max_by i min_by
    • max_by_key i min_by_key
    • Porównywanie sekwencji elementów
    • any i all
    • position, rposition oraz ExactSizeIterator
    • fold i rfold
    • try_fold i try_rfold
    • nth i nth_back
    • last
    • find, rfind i find_map
    • Tworzenie kolekcji: collect i FromIterator
    • Zestaw metod Extend
    • partition
    • for_each i try_for_each
  • Implementacja własnych iteratorów

Rozdział 16. Kolekcje

  • Przegląd kolekcji
  • Vec<T>
    • Dostęp do elementów
    • Iteracja
    • Zwiększanie i zmniejszanie wielkości wektora
    • Łączenie
    • Podział
    • Zamiana
    • Sortowanie i wyszukiwanie
    • Porównywanie podzbiorów
    • Elementy losowe
    • Reguły zapobiegające konfliktom w czasie iteracji
  • VecDeque<T>
  • BinaryHeap<T>
  • HashMap<K, V> i BTreeMap<K, V>
    • Entry
    • Iterowanie map
  • HashSet<T> i BTreeSet<T>
    • Iteracja zbioru
    • Kiedy równe wartości są różne
    • Operacje dotyczące całego zbioru
  • Haszowanie
  • Niestandardowe algorytmy haszujące
  • Kolekcje standardowe i co dalej?

Rozdział 17. Tekst i łańcuchy znaków

  • Podstawy Unicode
    • ASCII, Latin-1 i Unicode
    • UTF-8
    • Kierunek tekstu
  • Znaki (typ char)
    • Klasyfikacja znaków
    • Obsługa cyfr
    • Zmiana wielkości liter
    • Konwersja znaku do i z liczby całkowitej
  • Typy String i str
    • Tworzenie łańcuchów znaków
    • Prosta inspekcja
    • Dołączanie i wstawianie tekstu
    • Usuwanie i zastępowanie tekstu
    • Konwencje nazewnicze dotyczące wyszukiwania i iterowania
    • Wyszukiwanie tekstu i wzorce
    • Wyszukiwanie i zamiana
    • Iterowanie tekstu
    • Obcinanie
    • Zmiana wielkości liter w łańcuchach
    • Konwersja tekstu do wartości innego typu
    • Konwersja wartości innego typu do tekstu
    • Tworzenie referencji innego typu
    • Tekst jako UTF-8
    • Tworzenie tekstu na podstawie danych UTF-8
    • Alokacja warunkowa
    • Łańcuchy znaków jako kolekcje generyczne
  • Formatowanie wartości
    • Formatowanie tekstu
    • Formatowanie liczb
    • Formatowanie innych typów
    • Formatowanie wartości z myślą o debugowaniu
    • Formatowanie i debugowanie wskaźników
    • Wiązanie argumentów za pomocą indeksu i nazwy
    • Dynamiczne definiowanie długości i precyzji
    • Formatowanie własnych typów
    • Użycie języka formatowania we własnym kodzie
  • Wyrażenia regularne
    • Podstawowe użycie wyrażeń regularnych
    • Wyrażenia regularne w trybie leniwym
  • Normalizacja
    • Rodzaje normalizacji
    • Biblioteka unicode-normalization

Rozdział 18. Operacje wejścia - wyjścia

  • Obiekty typu reader i writer
    • Obiekty typu reader
    • Buforowany obiekt typu reader
    • Przeglądanie tekstu
    • Pobieranie tekstu
    • Obiekty typu writer
    • Pliki
    • Wyszukiwanie
    • Inne rodzaje obiektów reader i writer
    • Dane binarne, kompresja i serializacja
  • Pliki i katalogi
    • OsStr i Path
    • Metody typów Path i PathBuf
    • Funkcje dostępu do systemu plików
    • Odczyt zawartości katalogu
    • Funkcje bezpośrednio związane z platformą
  • Obsługa sieci

Rozdział 19. Programowanie współbieżne

  • Podział i łączenie wątków
    • spawn i join
    • Obsługa błędów w różnych wątkach
    • Współdzielenie niemutowalnych danych przez różne wątki
    • Rayon
    • Zbiór Mandelbrota raz jeszcze
  • Kanały
    • Wysyłanie wartości
    • Odczyt wartości
    • Uruchomienie potoku
    • Cechy kanałów i ich wydajność
    • Bezpieczeństwo wątków: Send i Sync
    • Współpraca iteratora i kanału
    • Potoki i co dalej?
  • Stan współdzielony mutowalny
    • Czym jest muteks?
    • Mutex<T>
    • mut i Mutex
    • Dlaczego Mutex to nie zawsze dobry pomysł?
    • Zakleszczenie (deadlock)
    • Zatruty muteks
    • Kanały z wieloma nadawcami stosujące muteksy
    • Blokady odczytu/zapisu (RwLock<T>)
    • Zmienne warunkowe (Condvar)
    • Typy atomowe
    • Zmienne globalne
  • Rust i pisanie programów wielowątkowych

Rozdział 20. Programowanie asynchroniczne

  • Od kodu synchronicznego do asynchronicznego
    • Interfejs Future
    • Funkcje asynchroniczne i wyrażenia await
    • Wywoływanie funkcji asynchronicznych z kodu synchronicznego: block_on
    • Uruchamianie asynchronicznych zadań
    • Asynchroniczne instrukcje blokowe
    • Tworzenie funkcji asynchronicznych z wykorzystaniem asynchronicznych instrukcji blokowych
    • Uruchamianie zadań asynchronicznych w pulach wątków
    • Czy operacje asynchroniczne implementują Send?
    • Wykonywanie długotrwałych obliczeń: yield_now i spawn_local
    • Porównanie różnych rozwiązań asynchronicznych
    • Rzeczywisty asynchroniczny klient HTTP
  • Asynchroniczny klient i serwer
    • Typy błędów i wyników
    • Protokół
    • Pobieranie danych od użytkownika: strumienie asynchroniczne
    • Wysyłanie pakietów
    • Pobieranie pakietów: więcej strumieni asynchronicznych
    • Funkcja main klienta
    • Funkcja main serwera
    • Obsługa połączeń z klientami: asynchroniczne muteksy
    • Tablica grup: muteksy synchroniczne
    • Grupy: kanały rozgłoszeniowe paczki tokio
  • Podstawowe wartości future i wykonawcy: kiedy warto ponownie sprawdzać wartość future?
    • Wywoływanie funkcji aktywujących: spawn_blocking
    • Implementacja funkcji block_on
  • Typ Pin i jego stosowanie
    • Dwa etapy życia danych typ future
    • Przypięte wskaźniki
    • Zestaw metod Unpin
  • Kiedy warto stosować kod asynchroniczny?

Rozdział 21. Makra

  • Podstawy
    • Rozwijanie makra
    • Niezamierzone skutki
    • Powtórzenia
  • Makra wbudowane
  • Debugowanie makr
  • Pisanie makra json!
    • Typy składników
    • Makra a rekurencja
    • Makra i zestawy metod
    • Zakres i higiena
    • Import i eksport makr
  • Unikanie błędów składniowych w procesie dopasowywania
  • macro_rules! i co dalej?

Rozdział 22. Kod niebezpieczny

  • Dlaczego niebezpieczny?
  • Bloki unsafe
  • Przykład: wydajny typ łańcucha znaków ASCII
  • Funkcje unsafe
  • Kod niebezpieczny czy funkcja niebezpieczna?
  • Działanie niezdefiniowane
  • Zestawy metod unsafe
  • Wskaźniki niechronione
    • Bezpieczne tworzenie dereferencji wskaźników niechronionych
    • Przykład: RefWithFlag
    • Wskaźniki dopuszczające wartość pustą
    • Rozmiary i rozmieszczanie typów
    • Operacje arytmetyczne na wskaźnikach
    • Wchodzenie do pamięci i wychodzenie z pamięci
    • Przykład: GapBuffer
    • Bezpieczeństwo błędów paniki w kodzie niebezpiecznym
  • Ponowna interpretacja pamięci z użyciem unii
  • Dopasowywanie unii
  • Pożyczanie unii

Rozdział 23. Funkcje obce

  • Wyszukiwanie wspólnych reprezentacji danych
  • Deklarowanie obcych funkcji i zmiennych
  • Korzystanie z funkcji i bibliotek
  • Interfejs niechroniony dla biblioteki libgit2
  • Interfejs bezpieczny dla biblioteki libgit2
  • Podsumowanie

Skorowidz

  • Tytuł: Programowanie w języku Rust. Wydajność i bezpieczeństwo. Wydanie II
  • Autor: Jim Blandy, Jason Orendorff, Leonora F. S. Tindall
  • Tytuł oryginału: Programming Rust: Fast, Safe Systems Development, 2nd Edition
  • Tłumaczenie: Piotr Rajca, Adam Bochenek, Krzysztof Sawka
  • ISBN: 978-83-283-9526-8, 9788328395268
  • Data wydania: 2022-11-22
  • Format: Ebook
  • Identyfikator pozycji: prrus2
  • Wydawca: Helion