Menu
Coddy logo textTech

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.

challenge icon

Aufgabe

Einfach

Lassen 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 eine BankAccount-Struktur im main-Paket, die ein reales Bankkonto mit angemessenem Datenschutz modelliert:
    • HolderName (exportiert) – der Name des Kontoinhabers, der sicher öffentlich angezeigt werden kann
    • AccountType (exportiert) – die Art des Kontos (z. B. "Savings", "Checking")
    • balance (nicht exportiert) – der tatsächliche Kontostand, der geschützt werden sollte
    • pin (nicht exportiert) – die Konto-PIN, hochsensible Daten
    Fügen Sie eine Konstruktorfunktion NewBankAccount hinzu, die den Namen des Inhabers, den Kontotyp, den Anfangskontostand und die PIN entgegennimmt und dann einen Zeiger auf ein neues BankAccount zurückgibt. Fügen Sie außerdem eine Methode GetPublicInfo() string hinzu, die das Format Account: [HolderName] ([AccountType]) zurückgibt.
  • main.go: Lesen Sie die Kontodetails aus der Eingabe ein, erstellen Sie ein BankAccount mit 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 (balance und pin) 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: Savings

Beachten 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
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung