Pola eksportowane i nieeksportowane
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 47 z 107.
W Go enkapsulacja na poziomie struktury jest kontrolowana przez wielkość liter w nazwach pól. Ta prosta zasada określa, czy można uzyskać dostęp do pól spoza pakietu, w którym zdefiniowano strukturę.
Pola zaczynające się od wielkiej litery są eksportowane: dostępne z każdego pakietu. Pola zaczynające się od małej litery są nieeksportowane: dostępne tylko w obrębie tego samego pakietu:
// W pakiecie "user"
type User struct {
Name string // Eksportowane – dostępne wszędzie
Email string // Eksportowane – dostępne wszędzie
password string // Nieeksportowane – dostępne tylko w pakiecie "user"
age int // Nieeksportowane – dostępne tylko w pakiecie "user"
}
Gdy inny pakiet importuje i używa tej struktury, może korzystać tylko z eksportowanych pól:
// W pakiecie "main"
import "user"
func main() {
u := user.User{
Name: "Alice", // działa
Email: "a@mail.com", // działa
// password: "secret", // błąd kompilacji: nieznane pole
}
fmt.Println(u.Name) // działa
// fmt.Println(u.password) // błąd kompilacji: nie można odwołać się do niewyeksportowanego pola
}
Ten mechanizm chroni poufne dane i wewnętrzne szczegóły implementacji. Pola password nie można odczytać ani zmodyfikować bezpośrednio spoza pakietu, co zmusza pozostały kod do korzystania z metod, które udostępniasz. To podejście Go do ukrywania danych: podstawowej zasady enkapsulacji w programowaniu obiektowym.
Wyzwanie
ŁatwyStwórzmy system konta bankowego, który pokazuje hermetyzację za pomocą pól eksportowanych i nieeksportowanych. Utworzysz pakiet, który chroni wrażliwe dane finansowe, jednocześnie udostępniając bezpieczne informacje publiczne.
Rozmieścisz swój kod w dwóch plikach:
account.go: Utwórz strukturęBankAccountw pakieciemain, która modeluje rzeczywiste konto bankowe z odpowiednią ochroną danych:HolderName(eksportowane) — imię i nazwisko posiadacza konta, które można bezpiecznie wyświetlać publicznieAccountType(eksportowane) — typ konta (np. "Savings", "Checking")balance(nieeksportowane) — rzeczywiste saldo, które powinno być chronionepin(nieeksportowane) — PIN do konta, dane o wysokim stopniu poufności
NewBankAccount, która przyjmuje imię i nazwisko posiadacza konta, typ konta, saldo początkowe i PIN, a następnie zwraca wskaźnik do nowej strukturyBankAccount. Dodaj też metodęGetPublicInfo() string, która zwraca tekst w formacie:Account: [HolderName] ([AccountType])main.go: Wczytaj dane konta z wejścia, utwórzBankAccountza pomocą konstruktora i pokaż działanie hermetyzacji. Wyświetl informacje publiczne za pomocą metody, a następnie uzyskaj bezpośredni dostęp do każdego eksportowanego pola i wyświetl je w osobnych wierszach. Pola nieeksportowane (balanceipin) są chronione. Możesz ustawić je tylko za pomocą konstruktora.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Imię i nazwisko posiadacza konta
- Wiersz 2: Typ konta
- Wiersz 3: Saldo początkowe (jako liczba zmiennoprzecinkowa)
- Wiersz 4: Kod PIN
Na przykład dla danych Alice Johnson, Savings, 5000.50 i 1234 wynik powinien wyglądać następująco:
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: SavingsZwróć uwagę, że saldo i PIN nigdy nie pojawiają się na wyjściu: są bezpiecznie ukryte wewnątrz struktury i dostępne tylko w obrębie pakietu. To właśnie działanie hermetyzacji: wrażliwe dane są chronione, a informacje publiczne pozostają dostępne.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Wczytaj imię i nazwisko posiadacza konta
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// Wczytaj typ konta
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// Wczytaj saldo początkowe
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// Wczytaj PIN
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: Utwórz nowy BankAccount za pomocą konstruktora
// account := NewBankAccount(...)
// TODO: Wyświetl informacje publiczne za pomocą metody GetPublicInfo()
// TODO: Wyświetl imię i nazwisko posiadacza, odwołując się bezpośrednio do eksportowanego pola
// fmt.Println("Holder:", ...)
// TODO: Wyświetl typ konta, odwołując się bezpośrednio do eksportowanego pola
// fmt.Println("Type:", ...)
// Uwaga: balance i pin nie są eksportowane — nie można uzyskać do nich bezpośredniego dostępu w tym miejscu
// Są bezpiecznie hermetyzowane w strukturze
_ = balance // Usuń tę linię, gdy użyjesz balance
_ = pin // Usuń tę linię, gdy użyjesz pin
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online