Exportierte vs. nicht exportierte Felder
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 47 von 107.
In Go wird die Kapselung auf Struct-Ebene durch die Groß- und Kleinschreibung von Feldnamen gesteuert. Diese einfache Regel bestimmt, ob auf Felder von außerhalb des Pakets, in dem das Struct definiert ist, zugegriffen werden kann.
Felder, die mit einem Großbuchstaben beginnen, sind exportiert – von jedem Paket aus zugänglich. Felder, die mit einem Kleinbuchstaben beginnen, sind nicht exportiert – nur innerhalb desselben Pakets zugänglich:
// Im Paket "user"
type User struct {
Name string // Exportiert - überall zugänglich
Email string // Exportiert - überall zugänglich
password string // Nicht exportiert - nur im Paket "user" zugänglich
age int // Nicht exportiert - nur im Paket "user" zugänglich
}
Wenn ein anderes Paket dieses Struct importiert und verwendet, kann es nur mit exportierten Feldern interagieren:
// Im Paket "main"
import "user"
func main() {
u := user.User{
Name: "Alice", // funktioniert
Email: "a@mail.com", // funktioniert
// password: "secret", // Kompilierfehler: unbekanntes Feld
}
fmt.Println(u.Name) // funktioniert
// fmt.Println(u.password) // Kompilierfehler: Verweis auf nicht exportiertes Feld nicht möglich
}
Dieser Mechanismus schützt sensible Daten und interne Implementierungsdetails. Das Feld password kann nicht direkt von außerhalb des Pakets gelesen oder geändert werden, was anderen Code dazu zwingt, die von Ihnen bereitgestellten Methoden zu verwenden. Dies ist der Ansatz von Go zur Erreichung von Data Hiding – ein Kernprinzip der Kapselung in der objektorientierten Programmierung.
Aufgabe
EinfachLassen Sie uns ein Bankkontosystem bauen, das Kapselung durch exportierte und nicht exportierte Felder demonstriert. Sie werden ein Paket erstellen, das sensible Finanzdaten schützt, während es sichere öffentliche Informationen bereitstellt.
Sie werden Ihren Code auf zwei Dateien verteilen:
account.go: Erstellen Sie eineBankAccount-Struktur immain-Paket, die ein reales Bankkonto mit angemessenem Datenschutz modelliert:HolderName(exportiert) – der Name des Kontoinhabers, der sicher öffentlich angezeigt werden kannAccountType(exportiert) – die Art des Kontos (z. B. "Savings", "Checking")balance(nicht exportiert) – der tatsächliche Kontostand, der geschützt werden solltepin(nicht exportiert) – die Konto-PIN, hochsensible Daten
NewBankAccounthinzu, die den Namen des Inhabers, den Kontotyp, den Anfangskontostand und die PIN entgegennimmt und dann einen Zeiger auf ein neuesBankAccountzurückgibt. Fügen Sie außerdem eine MethodeGetPublicInfo() stringhinzu, die das FormatAccount: [HolderName] ([AccountType])zurückgibt.main.go: Lesen Sie die Kontodetails aus der Eingabe ein, erstellen Sie einBankAccountmit dem Konstruktor und demonstrieren Sie die Kapselung. Geben Sie die öffentlichen Informationen mithilfe der Methode aus und greifen Sie dann direkt auf jedes exportierte Feld zu, um es in separaten Zeilen auszugeben. Die nicht exportierten Felder (balanceundpin) sind geschützt – Sie können sie nur über den Konstruktor setzen.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Name des Kontoinhabers
- Zeile 2: Kontotyp
- Zeile 3: Anfangskontostand (als Float)
- Zeile 4: PIN-Code
Zum Beispiel, gegeben Alice Johnson, Savings, 5000.50 und 1234, sollte Ihre Ausgabe wie folgt aussehen:
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: SavingsBeachten Sie, dass der Kontostand und die PIN niemals in der Ausgabe erscheinen – sie sind sicher innerhalb der Struktur verborgen und nur innerhalb des Pakets zugänglich. Dies ist Kapselung in Aktion: Sensible Daten sind geschützt, während öffentliche Informationen zugänglich bleiben.
Spickzettel
In Go wird die Kapselung durch die Groß- und Kleinschreibung von Feldnamen in Structs gesteuert:
- Großgeschriebene Felder sind exportiert (zugänglich von jedem Package)
- Kleingeschriebene Felder sind nicht exportiert (nur innerhalb desselben Packages zugänglich)
type User struct {
Name string // Exportiert - überall zugänglich
Email string // Exportiert - überall zugänglich
password string // Nicht exportiert - nur im selben Package zugänglich
age int // Nicht exportiert - nur im selben Package zugänglich
}
Wenn ein Struct aus einem anderen Package verwendet wird, sind nur exportierte Felder zugänglich:
import "user"
func main() {
u := user.User{
Name: "Alice", // funktioniert
Email: "a@mail.com", // funktioniert
// password: "secret", // Kompilierfehler: unbekanntes Feld
}
fmt.Println(u.Name) // funktioniert
// fmt.Println(u.password) // Kompilierfehler: Verweis auf nicht exportiertes Feld nicht möglich
}
Dieser Mechanismus schützt sensible Daten und interne Implementierungsdetails und zwingt externen Code dazu, bereitgestellte Methoden für den Zugriff zu verwenden.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Kontoinhaber-Namen lesen
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// Kontotyp lesen
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// Anfangssaldo lesen
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// PIN lesen
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: Erstelle ein neues BankAccount mit dem Konstruktor
// account := NewBankAccount(...)
// TODO: Gib die öffentlichen Informationen mit der Methode GetPublicInfo() aus
// TODO: Gib den Inhabernamen durch direkten Zugriff auf das exportierte Feld aus
// fmt.Println("Holder:", ...)
// TODO: Gib den Kontotyp durch direkten Zugriff auf das exportierte Feld aus
// fmt.Println("Type:", ...)
// Note: balance und pin sind nicht exportiert - auf sie kann hier nicht direkt zugegriffen werden
// Sie sind sicher innerhalb des struct gekapselt
_ = balance // Entferne diese Zeile, wenn du balance verwendest
_ = pin // Entferne diese Zeile, wenn du pin verwendest
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der Go OOP
Externe DateienGo Workspace & ModulePackages & ImportsExportierte vs. nicht-exportierte NamenEinführung in OOP in GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktor-FunktionenZusammenfassung – Einfacher Taschenrechner4Interfaces
Einführung in InterfacesImplizite ImplementierungInterface als VertragLeeres Interface (any)Type AssertionType SwitchInterface-KompositionStringer & Error InterfacesRückblick - Formen-Rechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf Paket-EbeneGetter- & Setter-MethodenInformation Hiding in GoZusammenfassung - Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterType ConstraintsGenerische StructsWorkaround für generische MethodenZusammenfassung – Generische Collection2Vertiefung: Typen & Structs
Basis- & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct TagsAnonyme StructsVerschachtelte StructsZero Values & StandardwerteZusammenfassung - Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen des Struct EmbeddingMethod PromotionEinbetten mehrerer StructsEmbedding vs. AggregationShadowing eingebetteter MethodenZusammenfassung – Mitarbeiter-Hierarchie8Fehlerbehandlung & OOP
Das error-InterfaceEigene FehlertypenError Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverZusammenfassung – Datei-Parser3Zeiger & Speicher
Zeiger-Grundlagen in GoZeiger auf StructsWertübergabe vs. ReferenzübergabeDie new() FunktionGarbage Collection in GoWiederholung – Linked List Builder6Polymorphismus in Go
Polymorphismus über InterfacesDuck Typing in GoInterface-ErfüllungsregelnPolymorphe CollectionsDependency InjectionZusammenfassung – Payment Processor9Nebenläufigkeit & OOP
Goroutines GrundlagenChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignZusammenfassung - Worker Pool