Tutorial: Create a Go Module — Deutsche Übersetzung
- Das Original:
-
https://golang.org/doc/tutorial/create-module
Version of February 12, 2021 - Diese Übersetzung:
-
https://bitloeffel.de/DOC/golang/create-module_20210309_de.html
Stand: 09.03.2021
© 2021 Hans-Werner Heinzen @ Bitloeffel.de
Die Nutzung dieses Werks ist unter den Bedingungen der "Creative Commons Attribution 3.0"-Lizenz erlaubt.
Für Fachbegriffe und ähnliches gibt es hier noch eine Wörterliste.
Übung: Module erstellen
Im Verlauf dieser Übung werden Sie zwei Module erstellen. Erstens eine Bibliothek, die von anderen Bibliotheken oder Programmen importiert werden kann. Zweitens ein Programm, welches das erste benutzt.
Diese Übung behandelt sieben Themen (in sieben Lektionen), die jeweils andere Aspekte der Sprache beleuchten.
- Erstellen eines Moduls — Schreiben Sie ein kleines Modul mit Funktionen, die Sie von einem anderen Modul rufen können.
- Rufen aus einem anderen Modul heraus — Importieren und benutzen Sie Ihr neues Modul.
- Rückgabe und Verarbeiten eines Fehlers — Fügen Sie eine einfache Fehlerbehandlung hinzu.
- Rückgabe einer zufälligen Grußformel — Verarbeiten Sie Daten mit Slices (das sind Arrays dynamischer Größe in Go).
- Rückgabe von Grußformeln für mehrere Adressaten — Speichern Sie Schlüssel/Wert-Paare in einer Map.
- Erstellen eines Tests — Benutzen Sie Go's Standardverfahren für Komponententests.
- Fertigen und Installieren der Anwendung — Fertigen und Installieren Sie Ihren Kode lokal.
Hinweis: Weitere Übungen finden Sie hier.
Voraussetzungen
- Etwas Programmiererfahrung. Der Kode hier ist recht einfach, aber es hilft, wenn man etwas über Funktionen, Schleifen und Arrays weiß.
- Ein Werkzeug zum Bearbeiten Ihres Kodes. Ein beliebiger Texteditor genügt; die meisten unterstützen das Arbeiten mit Go. Beliebt sind VSCode (frei), GoLand (kostet etwas) und Vim (frei).
- Ein Kommandofenster. Go arbeitet unter Linux oder Mac in jedem Terminal, und unter Windows in der PowerShell oder im cmd-Fenster.
1. Erstellen eines Moduls, das andere nutzen können
Beginnen wir mit dem Erstellen eines Go-Moduls (de). Ein Modul versammelt ein oder mehrere zusammengehörige Pakete, die einen eigenständigen, nützlichen Funktionssatz bilden. Zum Beispiel könnten Sie ein Modul mit Paketen zur Finanzanalyse erstellen, so dass andere, die eine Finanzanwendung schreiben, Ihre Vorarbeit nutzen können.
Go-Kode wird in Paketen gesammelt, und Pakete in Modulen. Das Modul eines Pakets benennt den Kontext, den Go benötigt um den Kode umzuwandeln; das ist zum einen die Version von Go, für das das Modul geschrieben wurde, und zum anderen die Menge der anderen Module, die gebraucht werden.
Im Laufe der Zeit ergänzen und verbessern Sie die Funktionalität Ihres Moduls und veröffentlichen immer neue Versionen. Entwickler, deren Kode Funktionen Ihres Moduls aufruft, können vor einer Produktionsübergabe das aktualisierte Paket importieren und mit der neuen Version testen.
-
In einer Kommandozeile begeben Sie sich in ihr Home-Verzeichnis.
Unter Linux oder Mac mit:
$ cd
Unter Windows mit:
cd %HOMEPATH%
-
Erstellen Sie für die Go-Modulquellen einen Ordner namens
greetings
. Dorthin schreiben Sie Ihren Kode.Das tun Sie zum Beispiel aus Ihrem Home-Verzeichnis heraus mit den folgenden Kommandos:
$ mkdir greetings $ cd greetings
-
Initialisieren Sie Ihr Modul mit dem Kommando
go mod init
, um die Datei go.mod zu erzeugen.Rufen Sie
go mod init
und geben Sie für das Modul den Pfadnamen mit, wo Ihr Kode zu finden sein wird. In unserem Beispiel verwenden wirexample.com/greetings
als Modulpfad — im Produktionskode wäre das dann die URL, von der Ihr Modul kopiert werden kann (download).$ go mod init example.com/greetings go: creating new go.mod: module example.com/greetings
Das Kommando
go mod init
erzeugt eine Datei go.mod, die Ihren Kode als nutzbares Modul erkennen lässt. Die gerade eben erzeugte Datei enthält nur den Namen Ihres Moduls und die Go-Version, mit der Ihr Kode funktioniert. Doch für jede Abhängigkeit, die Sie hinzufügen — also jedem Paket aus einem anderen Modul — wird die Datei go.mod das zugehörige Modul inklusive seiner Version festhalten. Damit bleiben Umwandlungen reproduzierbar, und Sie haben unmittelbare Kontrolle darüber, welche Modulversionen benutzt werden. - Erzeugen Sie mit einem Texteditor eine Datei für Ihren Kode und nennen sie greetings.go.
-
Fügen Sie dort den folgenden Kode ein, und sichern sie die Datei.
package greetings import "fmt" // Hello gibt einen Gruß an die genannte Person zurück. func Hello(name string) string { // Rückgabe eines Grußtexts mit eingefügtem Namen. message := fmt.Sprintf("Hi %v. Wie geht's.", name) return message }
Das ist der erste Kode für ihr Modul. Er gibt jedem Rufer, der danach fragt, einen Gruß zurück. In der nächsten Lektion werden wir dann Kode schreiben, der diese Funktion ruft.
Im obigen Kode tun Sie folgendes:
-
Sie deklarieren ein Paket
greetings
, um darin verwandte Funktionen zu sammeln. -
Sie implementieren eine Funktion
Hello
, die einen Gruß zurückgibt.Diese Funktion nimmt einen Parameter
name
vom Typstring
entgegen und gibt einenstring
zurück. In Go kann eine Funktion, deren Name mit einem Großbuchstaben beginnt, von einer Funktion außerhalb des Pakets gerufen werden. Das ist in Go als exportierter Name bekannt. -
Sie deklarieren eine Variable
message
die den Gruß aufnimmt.In Go ist der Operator
:=
eine Abkürzung zum Deklarieren und Initialisieren einer Variablen in einer Zeile. (Go erkennt am Wert auf der rechten Seite den Typ der Variablen.) In Langversion hätten Sie auch schreiben können:var message string message = fmt.Sprintf("Hi %v. Wie geht's.", name)
-
Sie benutzen die Funktion
Sprintf
aus dem Paketfmt
, um eine Grußnachricht zu erzeugen. Beim ersten Argument handelt es sich um einen Formatstring;Sprintf
ersetzt dort den Platzhalter%v
mit dem Wert des Parametersname
. Damit ist der Grußtext vollständig. - Sie geben den formatierten Grußtext an den Rufer zurück.
-
Sie deklarieren ein Paket
Im nächsten Schritt werden Sie diese Funktion von einem anderen Modul aus rufen.
2. Rufen aus einem anderen Modul heraus
In dieser Lektion werden wir Kode schreiben, der die
Hello
-Funktion des gerade erstellten Moduls ruft.
Unser Kode wird als Programm ausführbar sein und Kode des
greetings
-Moduls nutzen.
-
Erstellen Sie für die Go-Modulquellen einen Ordner namens
hello
. Dorthin schreiben Sie Ihren Kode.Wenn Sie sich gerade im
greetings
-Ordner befinden, können Sie das z.B. mit folgenden Kommandos tun:$ cd .. $ mkdir hello $ cd hello
-
Erzeugen Sie mit einem Texteditor im
hello
-Ordner eine Datei für Ihren Kode und nennen Sie sie hello.go. -
Schreiben Sie Kode, mit dem Sie unsere
Hello
-Funktion rufen und geben Sie den zurückgegebenen Wert aus.Dazu können Sie in hello.go den folgendes einfügen:
package main import ( "fmt" "example.com/greetings" ) func main() { // Gruß besorgen und ausgeben. message := greetings.Hello("Rosa") fmt.Println(message) }
Im obigen Kode tun Sie folgendes:
-
Sie deklarieren ein
main
-Paket. Als Programm ausführbarer Kode muss sich bei Go immain
-Paket befinden. -
Sie importieren zwei Pakete,
example.com/greetings
undfmt
. Damit bekommen Sie Zugriff auf (exportierte) Funktionen dieser Pakete. Indem Sieexample.com/greetings
importieren — das Paket, das sie vorhin erstellt haben — bekommen Sie Zugriff auf die FunktionHello
. Außerdem importieren Siefmt
, mit seinen Funktionen zur Ein- und Ausgabe von Text (wie etwa Ausgeben von Text auf die Konsole). -
Sie kommen an einen Grußformel, indem Sie die
Hello
-Funktion des Paketsgreetings
aufrufen.
-
Sie deklarieren ein
-
Erzeugen Sie für dieses
hello
-Paket ein neues Modul.Führen Sie dazu auf der Kommandozeile aus dem Ordner hello das Kommando
go mod init
mit einem Modulnamen aus (hier soll er nur "hello" lauten).$ go mod init hello go: creating new go.mod: module hello
-
Bearbeiten Sie jetzt das
hello
-Modul, um unser noch unveröffentlichtesgreetings
-Modul benutzen zu können.Für den produktiven Betrieb werden Sie wohl Ihr Modul auf einem Server veröffentlichen — entweder intern in Ihrer Firma oder im Internet — und das Go-Kommando wird es dann von dort kopieren können. Vorläufig aber müssen Sie das Modul des rufenden Programms modifizieren, damit der greetings-Kode auch in Ihrem lokalen Dateisystem gefunden wird.
Dazu ändern Sie die Datei go.mod des Moduls
hello
an einer Stelle.-
Öffen Sie im Ordner hello die Datei go.mod, ändern Sie wie
folgt und sichern die Datei wieder.
module hello go 1.14 replace example.com/greetings => ../greetings
Jetzt sagt die
replace
-Direktive dem Go-Kommando, es soll den Modulpfad, also die URLexample.com/greetings
mit dem von Ihnen angegebenen Pfad ersetzen (replace). Hier ist das der greetings-Ordner direkt nebem dem hello-Ordner. -
Im hello-Ordner starten Sie jetzt
go build
, damit Go das Modul lokalisiert und es als Abhängigkeit in der go.mod-Datei ergänzt.$ go build go: found example.com/greetings in example.com/greetings v0.0.0-00010101000000-000000000000
-
In der go.mod-Datei können Sie jetzt die Änderung sehen,
die mit
go build
vorgenommen wurde; das ist dierequire
-Direktive.module hello go 1.14 replace example.com/greetings => ../greetings require example.com/greetings v0.0.0-00010101000000-000000000000
Zum Umwandeln des Moduls fand Go den Kode lokal im Ordner ../greetings, fügte eine
require
-Direktive hinzu, die besagt, dasshello
vonexample.com/greetings
abhängt. Diese Abhängigkeit haben Sie erzeugt, indem Sie in hello.go dasgreetings
-Paket aus dem greetings-Modul importiert haben. Diereplace
-Direktive sagt Go, wo der Kode zu finden ist, weil der bis jetzt noch nicht veröffentlicht wurde.Für ein öffentliches Modul würde die go-mod-Datei die
replace
-Direktive nicht enthalten und nur mit derrequire
-Direktive und der dort angegebenen Versionsnummer arbeiten.require example.com/greetings v1.1.0
-
Öffen Sie im Ordner hello die Datei go.mod, ändern Sie wie
folgt und sichern die Datei wieder.
-
Um zu sehen, ob der Kode funktioniert starten Sie im hello-Ordner
die ausführbare Datei
hello
; diese wurde mitgo build
erzeugt.-
Unter Linux oder Mac mit:
$ ./hello Hi Rosa. Wie geht's.
-
Unter Windows mit:
$ hello.exe Hi Rosa. Wie geht's.
-
Unter Linux oder Mac mit:
Glückwunsch! Sie haben gerade zwei funktionierende Module geschrieben. Im nächsten Schritt werden Sie eine Fehlerbearbeitung ergänzen.
3. Rückgabe und Verarbeiten eines Fehlers
Handhaben von Fehlern ist für zuverlässigen Kode unverzichtbar. In dieser Lektion ergänzen Sie Kode, um einen Fehler aus dem greetings-Modul zurückzugeben und diesen dann im rufenden Programm zu verarbeiten.
-
Ergänzen Sie greetings/greetings.go um den weiter unten
hervorgehobenen Kode.
Es macht wenig Sinn, einen Gruß zurückzugeben, wenn nicht bekannt ist, wer gegrüßt werden soll. Geben Sie also einen Fehler an den Rufer zurück, wenn
name
leer ist. Kopieren Sie die entsprechenden Zeilen nach greetings.go und speichen die Datei.package greetings import ( "errors" "fmt" ) // Hello gibt einen Gruß an die genannte Person zurück. func Hello(name string) (string, error) { // Wenn kein Name, dann Fehler mit Fehlermeldung zurückgeben. if name == "" { return "", errors.New("Name leer") } // Wenn mit Name, dann // Rückgabe eines Grußtexts mit eingefügtem Namen. message := fmt.Sprintf("Hi %v. Wie geht's.", name) return message, nil }
Im obigen Kode tun Sie folgendes:
-
Sie Ändern die Funktion so, dass sie zwei Werte zurückgibt:
einen
string
und einerror
. Ihr Rufer wird den zweiten Wert prüfen und daran sehen, ob ein Fehler aufgetreten ist. (Funktionen in Go können mehrere Werte zurückgeben (de).) -
Sie importieren aus der Go-Standardbibliothek das Paket
errors
, um daraus die Funktionerrors.New
benutzen zu können. -
Sie fügen eine
if
-Anweisung hinzu, um auf eine ungültige Anfrage hin zu prüfen (ein leerer String, wo ein Name sein sollte), und in diesem Fall einen Fehler zurückzugeben. Die Funktionerrors.New
liefert einenerror
, der Ihre Fehlernachricht enthält. -
Für den Erfolgsfall ergänzen Sie
nil
(was heißen soll: kein Fehler) in derreturn
-Anweisung. Daran kann der Rufer erkennen, dass die Funktion erfolgreich war.
-
Sie Ändern die Funktion so, dass sie zwei Werte zurückgibt:
einen
-
Verarbeiten Sie in der Datei hello/hello.go den
error
-Wert, der nun von der FunktionHello
zusätzlich zu dem bisherigen Wert zurückgegeben wird.Ergänzen Sie hello.go um den hier hervorgehobenen Kode:
package main import ( "fmt" "log" "example.com/greetings" ) func main() { // Festlegen der Eigenschaften des Standard-Loggers: // ein Präfix für den Log-Eintrag und ein Schalter, der die // Ausgabe von Zeit, Quelldateiname und Zeilennummer unterbindet. log.SetPrefix("greetings: ") log.SetFlags(0) // Anfordern einer Grußnachricht message, err := greetings.Hello("") // Einen zurückgelieferter Fehler auf der Konsole ausgeben, // dann das Programm verlassen. if err != nil { log.Fatal(err) } // Wenn ohne Fehler, Ausgabe der Nachricht auf der Konsole. fmt.Println(message) }
Im obigen Kode tun Sie folgendes:
-
Sie richten das
log
-Paket so ein, dass am Beginn der Protokollnachricht der Kommandoname ("greetings"), aber keine Zeitangabe und keine Quelldateiinfos ausgegeben werden. -
Sie weisen beide Rückgabewerte von
Hello
Variablen zu, also auch denerror
-Wert. -
Sie vergessen Rosas Namen und geben als Argument für
Hello
einen leeren Sring mit, um so Ihre Fehlerverarbeitung testen zu können. -
Sie fragen nach einem Nicht-nil
error
-Wert. In diesem Fall ist weitermachen sinnlos. -
Sie nutzen Funktionen des
log
-Pakets aus der Standardbibliothek, um Ihre Fehlerinformation auszugeben. Tritt ein Fehler auf, so rufen Sie dessen FunktionFatal
zur Ausgabe und zum Abbrechen des Programms.
-
Sie richten das
-
Um zu bestätigen, dass der Kode funktioniert, starten Sie im hello-Ordner die hello.go-Datei mit
go run
.Da Sie einen leeren Namen mitgeben, tritt jetzt ein Fehler auf.
$ go run hello.go greetings: Name leer exit status 1
So einfach ist Fehlerbehandlung in Go: Geben Sie dem Rufer einen
error
als Wert zurück, damit er ihn prüfen kann.
Im nächsten Schritt
werden Sie ein Go-typisches Slice benutzen, um einen zufällig
gewählten Gruß zurückzugeben.
4. Rückgabe einer zufälligen Grußformel
In dieser Lektion ändern Sie den Kode so, dass er anstatt immer mit der gleichen Grußformel zu antworten eine von mehreren vorgefertigten Grußformeln zurückgibt.
Zu diesem Zweck benutzen Sie ein Slice. Ein Slice ist einem Array ähnlich, nur dass seine Größe sich dynamisch ändert, wenn Sie Elemente hinzufügen oder entfernen. Es ist einer der nützlichsten Typen in Go. Sie werden nun ein kleines Slice mit drei Grußformeln einfügen, und lassen Ihren Kode eine von diesen zufällig wählen und zurückgeben.
-
Ändern Sie greetings/greetings.go so, dass Ihr Kode wie dieser hier
ausschaut:
package greetings import ( "errors" "fmt" "math/rand" "time" ) // Hello gibt einen Gruß an die genannte Person zurück. func Hello(name string) (string, error) { // Wenn kein Name, dann Fehler mit Fehlermeldung zurückgeben. if name == "" { return "", errors.New("Name leer") } // Erzeugen eines Grußes in zufälliger ausgewählter Form. message := fmt.Sprintf(randomFormat(), name) return message, nil } // init versorgt Anfangswerte von Variablen, // die später in Funktionen benutzt werden. func init() { rand.Seed(time.Now().UnixNano()) } // randomFormat gibt aus einer Menge von Grußformeln // eine zurück; sie wird zufällig ausgewählt. func randomFormat() string { // Ein Slice von Formatstrings mit Grußformel. formats := []string{ "Hi %v. Wie geht's.", "Schön dich zu sehen, %v.", "%v! Habe die Ehre!", } // Zufällige Wahl einer Grußformel mithilfe eines // zufällig ermittelten Index für das Slice. return formats[rand.Intn(len(formats))] }
In diesem Kode tun Sie folgendes:
-
Sie fügen eine Funktion
randomFormat
hinzu, die ein zufällig ausgewähltes Grußformat zurückgibt. Beachten Sie, dassrandomFormat
mit einem Kleinbuchstaben beginnt, dass es also nur von Kode im selben Paket erreichbar ist; anders gesagt,randomFormat
wird nicht exportiert. -
Dort deklarieren Sie
formats
als Slice mit drei Grußformaten. Wenn ein Slice deklariert wird, enthält die eckige Klammer keine Größenangabe, wie hier bei[]string
. Damit sagt man Go, dass sich das Array, das hinter dem Slice steckt, dynamisch ändern kann. -
Sie benutzen das
math/rand
-Paket, um eine Zufallszahl zum Indexzugriff auf das Slice zu erhalten. -
Sie ergänzen eine
init
-Funktion (de), um dort dasrand
-Paket mit der aktuellen Zeit zu "impfen" (seed).init
-Funktionen führt Go automatisch bei Programmstart aus, nachdem die globalen Variablen initialisiert worden sind. -
Um einen Formatstring zu erhalten, rufen Sie in
Hello
dierandomFormat
-Funktion, und benutzen dieses Format zusammen mit dem Wert vonname
zum Erzeugen des Grußes. - Geben Sie — wie bisher — den Gruß (oder einen Fehler) zurück.
Das hello.go kann bleiben, wie es ist.
-
Sie fügen eine Funktion
-
Wechseln Sie auf der Kommandozeile in den hello-Ordner und starten
dort hello.go mit
go run
, um zu bestätigen, dass Ihr Kode funktioniert. Starten Sie mehrmals und beachten Sie die wechselden Grußformeln.Ah, Moment noch! — Vergessen Sie nicht den Namen Rosa (oder einen anderen nach Belieben) als Argument für den Aufruf der
Hello
-Funktion in hello.go:greetings.Hello("Rosa")
$ go build $ ./hello Schön dich zu sehen, Rosa. $ ./hello Hi Rosa. Wie geht's. $ ./hello Rosa! Habe die Ehre!
Das war eine Einführung in Go's Slices. Um aus diesem Datentyp noch mehr rauszuholen, wollen wir noch mit einem Slice mehrere Personen grüßen. Das geschieht im nächsten Schritt.
5. Rückgabe von Grußformeln für mehrere Adressaten
Als letzte Änderung an Ihrem Modulkode werden Sie die Fähigkeit hinzufügen, Grüße für mehrere Personen auf eine einzige Anfrage hin zurückzugeben. Anders formuliert verarbeiten wir eine Eingabe, die aus mehreren Werten besteht, zu einer Ausgabe, die ebenfalls mehrere Werte enthält.
Zu diesem Zweck müssen Sie eine Menge von Namen an eine Funktion
übergeben, die für jeden dieser Namen einen Gruß zurückgeben kann.
Eine Änderung des Parameters von Hello
von einem
Einzelwert zu einer Menge von Werten würde die Signatur dieser
Funktion ändern. Wenn Sie also das Modul greetings
schon veröffentlicht hätten und andere bereits in ihrem Kode
Hello
gerufen hätten, würden deren Programme
unbrauchbar. In so einem Fall ist es besser, neuen Fähigkeiten
auch neue Namen zu geben.
Die letzte Kodeänderung dieser Übung führen Sie so durch, als
hätten Sie bereits eine Version des greetings
-Moduls
veröffentlicht. Anstatt die Hello
-Funktion zu ändern,
fügen Sie eine neue Funktion Hellos
hinzu, die eine
Menge mit Namen entgegennimmt. Der Einfachheit halber soll die
neue Funktion die bisherige benutzen. So bleibt die ursprüngliche
für die schon vorhandenen Rufer erhalten (und für zukünftige, die
nur einen Gruß brauchen), und die neue bedient Rufer, die die
erweiterte Fähigkeit nutzen wollen.
-
Ändern Sie greetings/greetings.go so, dass Ihr Kode wie dieser hier
ausschaut:
package greetings import ( "errors" "fmt" "math/rand" "time" ) // Hello gibt einen Gruß an die genannte Person zurück. func Hello(name string) (string, error) { // Wenn kein Name, dann Fehler mit Fehlermeldung zurückgeben. if name == "" { return "", errors.New("Name leer") } // Erzeugen eines Grußes in zufälliger ausgewählter Form. message := fmt.Sprintf(randomFormat(), name) return message, nil } // Hellos gibt eine Map zurück, in der alle genannten Personen // mit einer Grußbotschaft verknüpft sind. func Hellos(names []string) (map[string]string, error) { // Eine Map, um Namen mit Grüßen zu verknüpfen. messages := make(map[string]string) // Iterieren über das mitgegebene Slice mit den Namen und // und Rufen der Hello-Funktion für jeden Namen. for _, name := range names { message, err := Hello(name) if err != nil { return nil, err } // Verknüpfen von Name und Gruß in der Map. messages[name] = message } return messages, nil } // init versorgt Anfangswerte von Variablen, // die später in Funktionen benutzt werden. func init() { rand.Seed(time.Now().UnixNano()) } // randomFormat gibt aus einer Menge von Grußformeln // eine zurück; sie wird zufällig ausgewählt. func randomFormat() string { // Ein Slice von Formatstrings mit Grußformel. formats := []string{ "Hi %v. Wie geht's.", "Schön dich zu sehen, %v.", "%v! Habe die Ehre!", } // Rückgabe einer zufällig ausgewählten Grußformel. return formats[rand.Intn(len(formats))] }
In diesem Kode tun Sie folgendes:
-
Sie fügen eine
Hellos
-Funktion hinzu, dessen Parameter ein Slice mit Namen anstelle des einzelnen Namens ist. Sie ändern weiterhin den Typ des ersten Ergebnistyps von einem String zu einer Map, damit Sie die Namen verknüpft mit den jeweiligen Grußbotschaften zurückgeben können. -
Sie lassen die neue
Hellos
-Funktion die schon bestehendeHello
-Funktion rufen. Damit stehen beide Funktionen zur Verfügung. -
Sie erzeugen für die Grüße eine
Map, die jeden
der Namen (als Schlüssel) mit dem erzeugten Gruß (als Wert)
verknüpft. In Go initialisiert man eine solche Map mit der
folgenden Sntax:
make(map[Schlüsseltyp]Wertetyp)
. Lassen SieHellos
diese Map an den Rufer zurückgeben. -
Sie iterieren über alle der Funktion mitgegebenen Namen,
stellen für jeden sicher, dass sein Wert nicht-leer ist,
und verknüpfen den Namen mit einer Grußbotschaft.
In der
for
-Schleife gibtrange
zwei Werte zurück: den Index und den Wert des aktuellen Elements. Den Index brauchen Sie nicht, also nutzen Sie den Leeren Bezeichner (de), (ein Unterstrich), um ihn zu ignorieren.
-
Sie fügen eine
-
In Ihrem hello/hello.go übergeben Sie ein Slice mit Namen und
geben dann den Inhalt der zurückerhaltenen Map aus.
Ändern Sie in hello.go den Kode so, dass er wie hier aussieht:
package main import ( "fmt" "log" "example.com/greetings" ) func main() { // Festlegen der Eigenschaften des Standard-Loggers: // ein Präfix für den Log-Eintrag und ein Schalter, der die // Ausgabe von Zeit, Quelldateiname und Zeilennummer unterbindet. log.SetPrefix("greetings: ") log.SetFlags(0) // Ein Slice mit Namen drin. names := []string{"Rosa", "Klara", "Karl"} // Anfordern der Grußnachrichten für die Namen. messages, err := greetings.Hellos(names) if err != nil { log.Fatal(err) } // Wenn ohne Fehler, Ausgabe der Map auf die Konsole. fmt.Println(messages) }
Mit diesem Änderungen tun Sie folgendes:
-
Sie legen eine Variable
names
als Slice-Typ mit drei Namen an. -
Sie übergeben die
names
-Variable als Argument an dieHellos
-Funktion.
-
Sie legen eine Variable
-
Um zu kontrollieren, dass der Kode auch funktioniert, wechseln Sie
auf der Kommandozeile in den Ordner hello und führen dort mit
go run
die Datei hello.go aus.Die Ausgabe ist eine Textdarstellung der Map, worin Namen mit Grüßen verknüpft sind, etwa so:
$ go run hello.go map[Karl:Karl! Habe die Ehre! Klara:Hi Klara. Wie geht's. Rosa:Schön dich zu sehen, Rosa.]
Diese Lektion stellte Ihnen Maps vor, um damit Schlüssel/Wert-Paare abzubilden. Sie zeigte außerdem den Gedanken vom Erhalt der Rückwärtskompatibilität auf. Im nächsten Schritt werden Sie die Standardmethode eines Komponententests für Ihren Kode kennenlernen.
6. Erstellen eines Tests
Nun, da Ihr Kode in einen stabilen Zustand ist (Gut gemacht!),
fügen Sie noch einen Test an. Testen während des Entwickelns kann
frühzeitig Fehler sichtbar machen, die sich mit den Änderungen
eingeschlichen haben. In dieser Lektion erstellen Sie einen Test
für die Hello
-Funktion.
Go's Standardverfahren für Komponententests macht es einfach, ganz
nebenbei zu testen. Mit ein paar Namenskonventionen, mit Go's
testing
-Paket und dem go test
-Kommando
können Sie Tests im Nu schreiben und ausführen.
-
Erstellen Sie im greetings-Ordner eine Datei mit Namen
greetings_test.go.
Endet der Dateiname auf _test.go, so signalisiert das dem
go
-Kommando, dass diese Datei Testfunktionen enthält. -
Fügen Sie folgenden Kode in greetings_test.go ein und sichern die
Datei.
package greetings import ( "testing" "regexp" ) // TestHelloName ruft greetings.Hello mit einem Namen // und prüft auf einen gültigen Rückgabewert. func TestHelloName(t *testing.T) { name := "Kurt" want := regexp.MustCompile(`\b`+name+`\b`) msg, err := Hello("Kurt") if !want.MatchString(msg) || err != nil { t.Fatalf(`Hello("Kurt") = %q, %v, erwartet: %#q, nil`, msg, err, want) } } // TestHelloEmpty ruft greetings.Hello mit einem leeren String // und prüft, ob auch ein Fehler zurückgegeben wurde. func TestHelloEmpty(t *testing.T) { msg, err := Hello("") if msg != "" || err == nil { t.Fatalf(`Hello("") = %q, %v, erwartet: "", error`, msg, err) } }
In diesem Kode tun Sie folgendes:
- Sie implementieren die Testfunktionen im selben Paket wie den zu testenden Kode.
-
Sie erstellen zwei Testfunktionen zum Testen der Funktion
greetings.Hello
. Testfunktionen haben Namen der FormTestName
, wobei Name den Test bezeichnet. Außerdem erwarten Testfunktionen als Parameter einen Zeiger auftesting.T
aus demtesting
-Paket. Diesen Parameter brauchen Sie in Ihrem Test für Meldungen und zum Protokollschreiben. -
Sie implementieren zwei Tests:
-
TestHelloName
ruft dieHello
- Funktion mit einem Wertname
, zu dem die Funktion eine gültige Nachricht zurückliefern soll. Sollte die Funktion einen Fehler oder eine unerwartete Nachricht (eine, die den Namen nicht enthält) zurückgeben, benutzen Sie die MethodeFatalf
des Parameterst
, um eine Meldung auf der Konsole auszugeben und die Testausführung zu beenden. -
TestHelloEmpty
ruft dieHello
- Funktion mit einem leeren String. Dieser Test soll bestätigen, dass Ihre Fehlerbehandlung funktioniert. Sollte die Funktion einen nicht-leeren String oder keinen Fehler zurückgeben, benutzen Sie die MethodeFatalf
des Parameterst
, um eine Meldung auf der Konsole auszugeben und die Testausführung zu beenden.
-
-
Zum Ausführen der Tests starten Sie von der Kommandozeile aus dem
greetings-Ordner heraus das Kommando
go test
.Das Kommando
go test
führt Testfunktionen (also solche, deren Namen mitTest
beginnen) aus Testdateien (also deren Namen mit _test.go enden) aus. Sie können auch den Schalter-v
(verbose) benutzen, um eine wortreiche Ausgabe mit der Liste aller Tests und deren Ergebnisse zu erhalten.Die Tests sollten erfolgreich sein.
$ go test PASS ok example.com/greetings 0.364s $ go test -v === RUN TestHelloName --- PASS: TestHelloName (0.00s) === RUN TestHelloEmpty --- PASS: TestHelloEmpty (0.00s) PASS ok example.com/greetings 0.372s
-
Pfuschen Sie nun in der
greetings.Hello
-Funktion, um mal einen scheiternden Test zu Gesicht zu bekommen.Die Testfunktion
TestHelloName
prüft den Rückgabewert für den derHello
-Funktion mitgegebenen Namen. Um ein Scheitern beobachten zu können, ändern Sie die Funktiongreetings.Hello
so, dass ihr Ergebnis nicht länger den Namen enthält.Ändern Sie die
Hello
-Funktion in greetings/greetings.go wie unten zu sehen. Beachten Sie, dass die hervorgehobenen Zeilen den Rückgabewert der Funktion so ändern, als wäre das Argumentname
versehenlich entfernt worden.// Hello gibt einen Gruß an die genannte Person zurück. func Hello(name string) (string, error) { // Wenn kein Name, dann Fehler mit Fehlermeldung zurückgeben. if name == "" { return "", errors.New("Name leer") } // Erzeugen eines Grußes in zufälliger ausgewählter Form. // message := fmt.Sprintf(randomFormat(), name) message := fmt.Sprint(randomFormat()) return message, nil }
-
Zum Ausführen der Tests starten Sie von der Kommandozeile aus dem
greetings-Ordner heraus das Kommando
go test
.Sie starten
go test
dieses Mal ohne den Schalter-v
. Die Ausgabe wird so nur Einzelheiten für die gescheiterten Tests enthalten, was übersichtlicher ist, wenn Sie viele Tests haben.TestHelloName
sollte scheitern,TestHelloEmpty
bleibt erfolgreich.$ go test --- FAIL: TestHelloName (0.00s) greetings_test.go:15: Hello("Kurt") = "Hi %v. Wie geht's.", <nil>, erwartet: `\bKurt\b`, nil FAIL exit status 1 FAIL example.com/greetings 0.182s
Diese Lektion stellte Go's Standardverfahren für Komponententests vor. Im nächsten Schritt werden Sie erfahren, wie man kompiliert und installiert, um den Kode lokal ausführen zu können.
7. Fertigen und Installieren der Anwendung
In dieser letzten Lektion lernen Sie ein neues
go
-Kommando kennen. Das bisher benutzte Kommando
go run
mag als Abkürzung nützlich sein, wenn ein
Eine-Datei-Programm umgewandelt und gestartet werden soll, es
erzeugt aber keine ausführbare Binärdatei, die man einfach
wiederholt starten könnte. Wenn Sie das wollen, ist das Kommando
go install
eine gute Wahl, denn es
wandelt ihren Kode um und installiert die erzeugte Binärdatei dort,
wo Sie sie starten können.
- Wechseln Sie auf der Kommandozeile in den Ordner, der hello.go enthält.
-
Finden Sie den Go-Installationspfad, also wo das
go
-Kommando das aktuelle Paket installieren wird.Den Installationspfad kann man ermitteln, indem man ein
go list
-Kommando der folgenden Form ausführt:$ go list -f '{{.Target}}'
Die Ausgabe ergibt beispielsweise
/home/gopher/bin/hello
, was bedeutet, dass Binärdateien nach /home/gopher/bin installiert werden. Diese Angabe brauchen Sie für den nächsten Schritt. -
Ergänzen Sie den Suchpfad Ihres Systems um den oben ermittelten
Go-Installationspfad.
So braucht ein Aufruf dann keine Angabe über den Ort Ihrer Binärdatei mehr.
-
Unter Linux oder Mac führen Sie folgendes Kommando aus:
$ export PATH=$PATH:/path/to/your/install/directory
-
Unter Windows führen Sie folgendes Kommando aus:
set PATH=%PATH%;C:\path\to\your\install\directory
Alternativ: Wenn bereits ein Ordner für Binärdateien wie
$HOME/bin
in Ihrem Suchpfad existiert, und wenn Sie dort Ihre Go-Programme installieren wollen, dann können Sie für Go das Installationsziel durch Setzen der GOBIN-Variablen ändern. Dazu nutzen Sie das Kommandogo env
in der folgenden Form:$ go env -w GOBIN=/path/to/your/bin
oder
go env -w GOBIN=C:\path\to\your\bin
-
Unter Linux oder Mac führen Sie folgendes Kommando aus:
-
Nachdem Sie den Suchpfad aktualisiert haben, starten Sie das
Kommando
go install
zum Kompilieren und Installieren des Pakets.$ go install
-
Starten Sie jetzt Ihre Anwendung ganz einfach mit deren Namen.
$ hello map[Karl:Karl! Habe die Ehre! Klara:Hi Klara. Wie geht's. Rosa:Rosa! Habe die Ehre!.]
Damit ist diese Übung zu Ende. Ein nächster Schritt, der viele weitere Eigenschaften von Go präsentiert, wäre die Rundreise durch Go, zu finden unter Tour of Go.