Golang-Tutorial
Was ist Go?
Go (auch bekannt als Golang) ist eine von Google entwickelte Open-Source-Programmiersprache. Es handelt sich um eine statisch typisierte, kompilierte Sprache. Go unterstรผtzt parallele Programmierung, d. h. es ermรถglicht die gleichzeitige Ausfรผhrung mehrerer Prozesse. Dies wird durch Kanรคle, Goroutinen usw. erreicht. Die Sprache Go verfรผgt รผber eine Garbage Collection, die selbst die Speicherverwaltung durchfรผhrt und die verzรถgerte Ausfรผhrung von Funktionen ermรถglicht.
In diesem Learn Go Language Tutorial lernen wir alle Grundlagen von Golang.
So laden Sie GO herunter und installieren es
Schritt 1) Gehe zu https://golang.org/dl/. Laden Sie die Binรคrdatei fรผr Ihr Betriebssystem herunter.
Schritt 2) Double Klicken Sie auf das Installationsprogramm und dann auf Ausfรผhren.
Schritt 3) Klicken Sie auf Weiter

Schritt 4) Wรคhlen Sie den Installationsordner aus und klicken Sie auf Weiter.

Schritt 5) Klicken Sie auf Fertig stellen, sobald die Installation abgeschlossen ist.

Schritt 6) Sobald die Installation abgeschlossen ist, kรถnnen Sie sie รผberprรผfen, indem Sie das Terminal รถffnen und Folgendes eingeben
go version
Dadurch wird die installierte Go-Version angezeigt

Ihr First-Go-Programm โ Go Hello World!
Erstellen Sie einen Ordner mit dem Namen โstudyGoโ. In diesem Tutorial zur Go-Sprache erstellen wir unsere Go-Programme in diesem Ordner. Go-Dateien werden mit der Erweiterung erstellt .gehen. Sie kรถnnen Go-Programme mithilfe der Syntax ausfรผhren
go run <filename>
Erstellen Sie eine Datei mit dem Namen first.go, fรผgen Sie den folgenden Code hinzu und speichern Sie ihn
package main
import ("fmt")
func main() {
fmt.Println("Hello World! This is my first Go program\n")
}

Navigieren Sie zu diesem Ordner in Ihrem Terminal. Fรผhren Sie das Programm mit dem Befehl aus
Geh zuerst laufen. Los
Sie kรถnnen den Ausgabedruck sehen
Hello World! This is my first Go program

Lassen Sie uns nun das obige Programm besprechen.
package main โ Jedes Go Language-Programm sollte mit einem Paketnamen beginnen. Go ermรถglicht uns die Verwendung von Paketen in anderen Go-Programmen und unterstรผtzt somit die Wiederverwendbarkeit von Code. Die Ausfรผhrung eines Go-Programms beginnt mit dem Code im Paket namens main.
import fmt โ importiert das Paket fmt. Dieses Paket implementiert die I/O-Funktionen.
func main() โ Dies ist die Funktion, von der aus die Programmausfรผhrung beginnt. Die Hauptfunktion sollte immer im Hauptpaket platziert werden. Unter main() kรถnnen Sie den Code in { } schreiben.
fmt.Println โ Dadurch wird der Text mithilfe der Println-Funktion von fmt auf dem Bildschirm gedruckt.
Hinweis: Wenn Sie in den folgenden Abschnitten dieses Go-Tutorials โCode ausfรผhren/ausfรผhrenโ erwรคhnen, bedeutet dies, dass Sie den Code in einer Datei mit der Erweiterung โ.goโ speichern und ihn mithilfe der Syntax ausfรผhren
go run <filename>
Datentypen
Typen (Datentypen) stellen den Typ des in einer Variablen gespeicherten Werts, den Typ des von einer Funktion zurรผckgegebenen Werts usw. dar.
Es gibt drei Grundtypen in Go Language
Numerische Typen โ Stellt numerische Werte dar, darunter Ganzzahlen, Gleitkommazahlen und komplexe Werte. Verschiedene numerische Typen sind:
int8 โ 8-Bit-Ganzzahlen mit Vorzeichen.
int16 โ 16-Bit-Ganzzahlen mit Vorzeichen.
int32 โ 32-Bit-Ganzzahlen mit Vorzeichen.
int64 โ 64-Bit-Ganzzahlen mit Vorzeichen.
uint8 โ 8-Bit-Ganzzahlen ohne Vorzeichen.
uint16 โ 16-Bit-Ganzzahlen ohne Vorzeichen.
uint32 โ 32-Bit-Ganzzahlen ohne Vorzeichen.
uint64 โ 64-Bit-Ganzzahlen ohne Vorzeichen.
float32 โ 32-Bit-Gleitkommazahlen.
float64 โ 64-Bit-Gleitkommazahlen.
complex64 โ hat Float32-Real- und Imaginรคrteile.
complex128 โ hat Float32-Real- und Imaginรคrteile.
String-Typen โ Stellt eine Folge von Bytes (Zeichen) dar. Sie kรถnnen verschiedene Operationen an Zeichenfolgen durchfรผhren, z. B. Zeichenfolgenverkettung, Extrahieren von Teilzeichenfolgen usw.
Boolesche Typen โ Stellt zwei Werte dar, entweder wahr oder falsch.
Golang-Schnittstelle
Golang-Schnittstelle ist eine Sammlung von Methodensignaturen, die von einem Typ verwendet werden, um das Verhalten von Objekten zu implementieren. Das Hauptziel der Golang-Schnittstelle besteht darin, Methodensignaturen mit Namen, Argumenten und Rรผckgabetypen bereitzustellen. Es liegt an einem Typ, die Methode zu deklarieren und zu implementieren. Eine Schnittstelle in Golang kann mit dem Schlรผsselwort โinterfaceโ deklariert werden.
Variablen
Variablen verweisen auf einen Speicherort, der einen Wert speichert. Der Typparameter (in der folgenden Syntax) stellt den Werttyp dar, der am Speicherort gespeichert werden kann.
Variable kann mithilfe der Syntax deklariert werden
var <variable_name> <type>
Sobald Sie eine Variable eines Typs deklariert haben, kรถnnen Sie die Variable jedem Wert dieses Typs zuweisen.
Sie kรถnnen einer Variablen auch wรคhrend der Deklaration selbst einen Anfangswert zuweisen mit
var <variable_name> <type> = <value>
Wenn Sie die Variable mit einem Anfangswert deklarieren, leiten Sie den Typ der Variablen aus dem Typ des zugewiesenen Werts ab. Sie kรถnnen den Typ also bei der Deklaration mithilfe der Syntax weglassen
var <variable_name> = <value>
Auรerdem kรถnnen Sie mit der Syntax mehrere Variablen deklarieren
var <variable_name1>, <variable_name2> = <value1>, <value2>
Das folgende Programm in diesem Go-Tutorial enthรคlt einige Golang-Beispiele fรผr Variablendeklarationen
package main
import "fmt"
func main() {
//declaring a integer variable x
var x int
x=3 //assigning x the value 3
fmt.Println("x:", x) //prints 3
//declaring a integer variable y with value 20 in a single statement and prints it
var y int=20
fmt.Println("y:", y)
//declaring a variable z with value 50 and prints it
//Here type int is not explicitly mentioned
var z=50
fmt.Println("z:", z)
//Multiple variables are assigned in single line- i with an integer and j with a string
var i, j = 100,"hello"
fmt.Println("i and j:", i,j)
}
Die Ausgabe wird sein
x: 3 y: 20 z: 50 i and j: 100 hello
Go Language bietet auch eine einfache Mรถglichkeit, Variablen mit Werten zu deklarieren, indem das Schlรผsselwort var weggelassen wird
<variable_name> := <value>
Beachten Sie, dass Sie verwendet haben := statt =. Sie kรถnnen := nicht einfach verwenden, um einer bereits deklarierten Variablen einen Wert zuzuweisen. := wird zum Deklarieren und Zuweisen von Werten verwendet.
Erstellen Sie eine Datei namens assign.go mit dem folgenden Code
package main
import ("fmt")
func main() {
a := 20
fmt.Println(a)
//gives error since a is already declared
a := 30
fmt.Println(a)
}
Fรผhren Sie โGo Run Assign.goโ aus, um das Ergebnis anzuzeigen
./assign.go:7:4: no new variables on left side of :=
Ohne Anfangswert deklarierte Variablen haben fรผr numerische Typen den Wert 0, fรผr boolesche Typen den Wert false und fรผr Zeichenfolgen eine leere Zeichenfolge
Konstante
Konstante Variablen sind Variablen, deren Wert nach der Zuweisung nicht mehr geรคndert werden kann. Eine Konstante in der Programmiersprache Go wird mit dem Schlรผsselwort โconstโ deklariert.
Erstellen Sie eine Datei namens constant.go und mit dem folgenden Code
package main
import ("fmt")
func main() {
const b =10
fmt.Println(b)
b = 30
fmt.Println(b)
}
Fรผhren Sie go run konstant.go aus, um das Ergebnis als anzuzeigen
.constant.go:7:4: cannot assign to b
Beispiele fรผr For-Schleifen
Schleifen werden verwendet, um einen Anweisungsblock basierend auf einer Bedingung wiederholt auszufรผhren. Die meisten Programmiersprachen bieten drei Arten von Schleifen: for, while, do while. Die Programmiersprache Go unterstรผtzt jedoch nur die for-Schleife.
Die Syntax einer Golang for-Schleife lautet
for initialisation_expression; evaluation_expression; iteration_expression{
// one or more statement
}
Der Initialisierungsausdruck wird zuerst (und nur einmal) in der Golang-for-Schleife ausgefรผhrt.
Dann wird der Wert โevaluation_expressionโ ausgewertet und wenn er wahr ist, wird der Code im Block ausgefรผhrt.
Die Iteration_Expression-ID wird ausgefรผhrt und der Evaluation_Expression wird erneut ausgewertet. Wenn es wahr ist, wird der Anweisungsblock erneut ausgefรผhrt. Dies wird so lange fortgesetzt, bis der Wert โevaluation_expressionโ โfalseโ wird.
Kopieren Sie das folgende Programm in eine Datei und fรผhren Sie es aus, um zu sehen, wie die Golang-for-Schleife Zahlen von 1 bis 5 druckt
package main
import "fmt"
func main() {
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
}
}
Ausgabe ist
1 2 3 4 5
Ansonsten
If else ist eine bedingte Anweisung. Die Synax ist
if condition{
// statements_1
}else{
// statements_2
}
Hier wird die Bedingung ausgewertet und wenn sie wahr ist, werden Anweisungen_1 ausgefรผhrt, andernfalls werden Anweisungen_2 ausgefรผhrt.
Sie kรถnnen die if-Anweisung auch ohne else verwenden. Sie kรถnnen auch verkettete if else-Anweisungen verwenden. Die folgenden Programme erklรคren mehr darรผber, wenn sonst.
Fรผhren Sie das folgende Programm aus. Es prรผft, ob eine Zahl x kleiner als 10 ist. Wenn ja, wird โx ist kleiner als 10โ ausgegeben.
package main
import "fmt"
func main() {
var x = 50
if x < 10 {
//Executes if x < 10
fmt.Println("x is less than 10")
}
}
Da hier der Wert von x grรถรer als 10 ist, wird die Anweisung innerhalb der Blockbedingung nicht ausgefรผhrt.
Sehen Sie sich nun das folgende Programm an. In diesem Tutorial zur Programmiersprache Go haben wir einen else-Block, der ausgefรผhrt wird, wenn die if-Auswertung fehlschlรคgt.
package main
import "fmt"
func main() {
var x = 50
if x < 10 {
//Executes if x is less than 10
fmt.Println("x is less than 10")
} else {
//Executes if x >= 10
fmt.Println("x is greater than or equals 10")
}
}
Dieses Programm gibt Ihnen eine Ausgabe
x is greater than or equals 10
In diesem Go-Tutorial sehen wir nun ein Programm mit mehreren if else-Blรถcken (verkettete if else-Blรถcke). Fรผhren Sie das folgende Go-Beispiel aus. Es prรผft, ob eine Zahl kleiner als 10 ist, zwischen 10 und 90 liegt oder grรถรer als 90 ist.
package main
import "fmt"
func main() {
var x = 100
if x < 10 {
//Executes if x is less than 10
fmt.Println("x is less than 10")
} else if x >= 10 && x <= 90 {
//Executes if x >= 10 and x<=90
fmt.Println("x is between 10 and 90")
} else {
//Executes if both above cases fail i.e x>90
fmt.Println("x is greater than 90")
}
}
Hier prรผft zunรคchst die if-Bedingung, ob x kleiner als 10 ist und nicht. Daher prรผft es die nรคchste Bedingung (sonst wenn), ob sie zwischen 10 und 90 liegt, was ebenfalls falsch ist. Anschlieรend wird der Block unter dem else-Abschnitt ausgefรผhrt, der die Ausgabe liefert
x is greater than 90
Schalter
Switch ist eine weitere bedingte Anweisung. Switch-Anweisungen werten einen Ausdruck aus und das Ergebnis wird mit einer Reihe verfรผgbarer Werte (Fรคlle) verglichen. Sobald eine รbereinstimmung gefunden wird, werden die mit dieser รbereinstimmung (Fall) verknรผpften Anweisungen ausgefรผhrt. Wenn keine รbereinstimmung gefunden wird, wird nichts ausgefรผhrt. Sie kรถnnen dem Switch auch einen Standardfall hinzufรผgen, der ausgefรผhrt wird, wenn keine anderen รbereinstimmungen gefunden werden. Die Syntax des Schalters lautet
switch expression {
case value_1:
statements_1
case value_2:
statements_2
case value_n:
statements_n
default:
statements_default
}
Dabei wird der Wert des Ausdrucks mit den jeweiligen Werten verglichen. Sobald eine รbereinstimmung gefunden wird, werden die mit diesem Fall verknรผpften Anweisungen ausgefรผhrt. Wenn keine รbereinstimmung gefunden wird, werden die Anweisungen im Standardabschnitt ausgefรผhrt.
Fรผhren Sie das folgende Programm aus
package main
import "fmt"
func main() {
a,b := 2,1
switch a+b {
case 1:
fmt.Println("Sum is 1")
case 2:
fmt.Println("Sum is 2")
case 3:
fmt.Println("Sum is 3")
default:
fmt.Println("Printing default")
}
}
Sie erhalten die Ausgabe als
Sum is 3
รndern Sie den Wert von a und b auf 3 und das Ergebnis wird sein
Printing default
Sie kรถnnen auch mehrere Werte in einem Fall angeben, indem Sie diese durch ein Komma trennen.
Arrays
Ein Array stellt eine benannte Folge fester Grรถรe von Elementen desselben Typs dar. Sie kรถnnen kein Array haben, das sowohl Ganzzahlen als auch Zeichen enthรคlt. Sie kรถnnen die Grรถรe eines Arrays nicht mehr รคndern, nachdem Sie die Grรถรe definiert haben.
Die Syntax zum Deklarieren eines Arrays lautet
var arrayname [size] type
Jedem Array-Element kann mithilfe der Syntax ein Wert zugewiesen werden
arrayname [index] = value
Der Array-Index beginnt bei 0 bis Grรถรe 1.
Mithilfe der Syntax kรถnnen Sie Array-Elementen bei der Deklaration Werte zuweisen
arrayname := [size] type {value_0,value_1,โฆ,value_size-1}
Sie kรถnnen den Grรถรenparameter auch ignorieren, wรคhrend Sie das Array mit Werten deklarieren, indem Sie size durch ersetzen ... und der Compiler ermittelt die Lรคnge anhand der Anzahl der Werte. Syntax ist
arrayname := [โฆ] type {value_0,value_1,โฆ,value_size-1}
Sie kรถnnen die Lรคnge des Arrays mithilfe der Syntax ermitteln
len(arrayname)
Fรผhren Sie das folgende Go-Beispiel aus, um das Array zu verstehen
package main
import "fmt"
func main() {
var numbers [3] string //Declaring a string array of size 3 and adding elements
numbers[0] = "One"
numbers[1] = "Two"
numbers[2] = "Three"
fmt.Println(numbers[1]) //prints Two
fmt.Println(len(numbers)) //prints 3
fmt.Println(numbers) // prints [One Two Three]
directions := [...] int {1,2,3,4,5} // creating an integer array and the size of the array is defined by the number of elements
fmt.Println(directions) //prints [1 2 3 4 5]
fmt.Println(len(directions)) //prints 5
//Executing the below commented statement prints invalid array index 5 (out of bounds for 5-element array)
//fmt.Println(directions[5])
}
Ausgang
Two 3 [One Two Three] [1 2 3 4 5] 5
Golang Slice- und Append-Funktion
Ein Slice ist ein Teil oder Segment eines Arrays. Oder es ist eine Ansicht oder Teilansicht eines zugrunde liegenden Arrays, auf das es zeigt. Sie kรถnnen auf die Elemente eines Slice zugreifen, indem Sie den Slice-Namen und die Indexnummer verwenden, genau wie in einem Array. Sie kรถnnen die Lรคnge eines Arrays nicht รคndern, wohl aber die Grรถรe eines Slice.
Der Inhalt eines Slice ist eigentlich der Zeiger auf die Elemente eines Arrays. Es bedeutet Wenn Sie ein Element in einem Slice รคndern, wirkt sich dies auch auf den zugrunde liegenden Array-Inhalt aus.
Die Syntax zum Erstellen eines Slice lautet
var slice_name [] type = array_name[start:end]
Dadurch wird ein Slice mit dem Namen โslice_nameโ aus einem Array mit dem Namen โarray_nameโ mit den Elementen am Indexanfang bis Ende-1 erstellt.
In diesem Golang-Tutorial fรผhren wir nun das folgende Programm aus. Das Programm erstellt einen Slice aus dem Array und druckt ihn aus. Auรerdem kรถnnen Sie sehen, dass eine รnderung des Inhalts im Slice das tatsรคchliche Array รคndert.
package main
import "fmt"
func main() {
// declaring array
a := [5] string {"one", "two", "three", "four", "five"}
fmt.Println("Array after creation:",a)
var b [] string = a[1:4] //created a slice named b
fmt.Println("Slice after creation:",b)
b[0]="changed" // changed the slice data
fmt.Println("Slice after modifying:",b)
fmt.Println("Array after slice modification:",a)
}
Dadurch wird das Ergebnis als gedruckt
Array after creation: [one two three four five] Slice after creation: [two three four] Slice after modifying: [changed three four] Array after slice modification: [one changed three four five]
Es gibt bestimmte Funktionen wie Golang len und Golang append, die Sie auf Slices anwenden kรถnnen
len(slice_name) โ gibt die Lรคnge des Slice zurรผck
append(slice_name, value_1, value_2) โ Golang append wird verwendet, um value_1 und value_2 an ein vorhandenes Slice anzuhรคngen.
append(slice_nale1,slice_name2โฆ) โ hรคngt Slice_name2 an Slice_name1 an
Fรผhren Sie das folgende Programm aus.
package main
import "fmt"
func main() {
a := [5] string {"1","2","3","4","5"}
slice_a := a[1:3]
b := [5] string {"one","two","three","four","five"}
slice_b := b[1:3]
fmt.Println("Slice_a:", slice_a)
fmt.Println("Slice_b:", slice_b)
fmt.Println("Length of slice_a:", len(slice_a))
fmt.Println("Length of slice_b:", len(slice_b))
slice_a = append(slice_a,slice_b...) // appending slice
fmt.Println("New Slice_a after appending slice_b :", slice_a)
slice_a = append(slice_a,"text1") // appending value
fmt.Println("New Slice_a after appending text1 :", slice_a)
}
Die Ausgabe wird sein
Slice_a: [2 3] Slice_b: [two three] Length of slice_a: 2 Length of slice_b: 2 New Slice_a after appending slice_b : [2 3 two three] New Slice_a after appending text1 : [2 3 two three text1]
Das Programm erstellt zunรคchst 2 Slices und gibt deren Lรคnge aus. Dann wurde ein Slice an ein anderes angehรคngt und dann eine Zeichenfolge an das resultierende Slice angehรคngt.
Funktionen
Eine Funktion stellt einen Block von Anweisungen dar, der eine bestimmte Aufgabe ausfรผhrt. Eine Funktionsdeklaration teilt uns den Funktionsnamen, den Rรผckgabetyp und die Eingabeparameter mit. Die Funktionsdefinition stellt den in der Funktion enthaltenen Code dar. Die Syntax zum Deklarieren der Funktion lautet
func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}
Die Parameter und Rรผckgabetypen sind optional. Auรerdem kรถnnen Sie von einer Funktion mehrere Werte zurรผckgeben.
Lassen Sie uns nun in diesem Golang-Tutorial das folgende Golang-Beispiel ausfรผhren. Hier akzeptiert die Funktion โcalcโ 2 Zahlen, fรผhrt die Addition und Subtraktion durch und gibt beide Werte zurรผck.
package main
import "fmt"
//calc is the function name which accepts two integers num1 and num2
//(int, int) says that the function returns two values, both of integer type.
func calc(num1 int, num2 int)(int, int) {
sum := num1 + num2
diff := num1 - num2
return sum, diff
}
func main() {
x,y := 15,10
//calls the function calc with x and y an d gets sum, diff as output
sum, diff := calc(x,y)
fmt.Println("Sum",sum)
fmt.Println("Diff",diff)
}
Die Ausgabe wird sein
Sum 25 Diff 5
Angebote
Zur Organisation des Codes werden Pakete verwendet. Bei einem groรen Projekt ist es nicht mรถglich, Code in einer einzigen Datei zu schreiben. Die Programmiersprache Go ermรถglicht es uns, den Code in verschiedenen Paketen zu organisieren. Dies erhรถht die Lesbarkeit und Wiederverwendbarkeit des Codes. Ein ausfรผhrbares Go-Programm sollte ein Paket namens main enthalten und die Programmausfรผhrung beginnt mit der Funktion namens main. Mithilfe der Syntax kรถnnen Sie andere Pakete in unser Programm importieren
import package_name
Wir werden in diesem Golang-Tutorial sehen und besprechen, wie man im folgenden Golang-Beispiel Pakete erstellt und verwendet.
Schritt 1) Erstellen Sie eine Datei mit dem Namen package_example.go und fรผgen Sie den folgenden Code hinzu
package main
import "fmt"
//the package to be created
import "calculation"
func main() {
x,y := 15,10
//the package will have function Do_add()
sum := calculation.Do_add(x,y)
fmt.Println("Sum",sum)
}
Im obigen Programm handelt es sich bei fmt um ein Paket, das uns die Programmiersprache Go hauptsรคchlich fรผr E/A-Zwecke zur Verfรผgung stellt. Auรerdem kรถnnen Sie ein Paket mit dem Namen โCalculationโ sehen. Innerhalb von main() sehen Sie eine Schrittsumme := Berechnung.Do_add(x,y). Das bedeutet, dass Sie die Funktion Do_add aus der Paketberechnung aufrufen.
Schritt 2) Zuerst sollten Sie die Paketberechnung in einem Ordner mit demselben Namen im SRC-Ordner von unterwegs erstellen. Der installierte Pfad von go kann aus der PATH-Variablen ermittelt werden.
Suchen Sie fรผr Mac den Pfad, indem Sie echo $PATH ausfรผhren

Der Pfad lautet also /usr/local/go
Suchen Sie unter Windows den Pfad durch Ausfรผhren von echo %GOROOT%

Hier ist der Pfad C:\Go\
Schritt 3) Navigieren Sie zum Ordner โsrcโ (/usr/local/go/src fรผr Mac und C:\Go\src fรผr Windows). Der Paketname aus dem Code lautet nun โCalculationโ. Go erfordert, dass das Paket in einem gleichnamigen Verzeichnis unter dem Verzeichnis โsrcโ abgelegt wird. Erstellen Sie ein Verzeichnis mit dem Namen โCalculationโ im Ordner โsrcโ.
Schritt 4) Erstellen Sie eine Datei mit dem Namen calc.go (Sie kรถnnen einen beliebigen Namen angeben, aber der Paketname im Code ist wichtig. Hier sollte es Berechnung sein) im Berechnungsverzeichnis und fรผgen Sie den folgenden Code hinzu
package calculation
func Do_add(num1 int, num2 int)(int) {
sum := num1 + num2
return sum
}
Schritt 5) Fรผhren Sie den Befehl go install aus dem Berechnungsverzeichnis aus, um calc.go zu kompilieren.

Schritt 6) Gehen Sie nun zurรผck zu package_example.go und fรผhren Sie go run package_example.go aus. Die Ausgabe wird Summe 25 sein.
Beachten Sie, dass der Name der Funktion Do_add mit einem Groรbuchstaben beginnt. Dies liegt daran, dass in Go der Funktionsname, wenn er mit einem Groรbuchstaben beginnt, bedeutet, dass andere Programme ihn sehen (auf ihn zugreifen) kรถnnen, andernfalls kรถnnen andere Programme nicht darauf zugreifen. Wenn der Funktionsname do_add wรคre, hรคtten Sie den Fehler erhalten
kann nicht auf den nicht exportierten Namen โcalculation.calcโ verweisen.
Aufschieben und Stapeln von Aufschรผben
Defer-Anweisungen werden verwendet, um die Ausfรผhrung eines Funktionsaufrufs zu verzรถgern, bis die Funktion, die die Defer-Anweisung enthรคlt, die Ausfรผhrung abgeschlossen hat.
Lassen Sie uns dies anhand eines Beispiels lernen:
package main
import "fmt"
func sample() {
fmt.Println("Inside the sample()")
}
func main() {
//sample() will be invoked only after executing the statements of main()
defer sample()
fmt.Println("Inside the main()")
}
Die Ausgabe wird sein
Inside the main() Inside the sample()
Hier wird die Ausfรผhrung von sample() verzรถgert, bis die Ausfรผhrung der einschlieรenden Funktion (main()) abgeschlossen ist.
Beim Stacking-Defer werden mehrere Defer-Anweisungen verwendet. Angenommen, Sie haben mehrere Defer-Anweisungen innerhalb einer Funktion. Go platziert alle verzรถgerten Funktionsaufrufe in einem Stapel, und sobald die umschlieรende Funktion zurรผckkehrt, werden die gestapelten Funktionen im ausgefรผhrt LIFO-Reihenfolge (Last In First Out). Sie kรถnnen dies im folgenden Beispiel sehen.
Fรผhren Sie den folgenden Code aus
package main
import "fmt"
func display(a int) {
fmt.Println(a)
}
func main() {
defer display(1)
defer display(2)
defer display(3)
fmt.Println(4)
}
Die Ausgabe wird sein
4 3 2 1
Hier wird zuerst der Code in main() ausgefรผhrt, und dann werden die verzรถgerten Funktionsaufrufe in umgekehrter Reihenfolge ausgefรผhrt, also 4, 3,2,1.
Pointers
Bevor wir Zeiger erklรคren, besprechen wir zunรคchst den Operator โ&โ. Der Operator โ&โ wird verwendet, um die Adresse einer Variablen abzurufen. Das bedeutet, dass โ&aโ die Speicheradresse der Variablen a ausgibt.
In diesem Golang-Tutorial fรผhren wir das folgende Programm aus, um den Wert einer Variablen und die Adresse dieser Variablen anzuzeigen
package main
import "fmt"
func main() {
a := 20
fmt.Println("Address:",&a)
fmt.Println("Value:",a)
}
Das Ergebnis wird sein
Address: 0xc000078008 Value: 20
Eine Zeigervariable speichert die Speicheradresse einer anderen Variablen. Sie kรถnnen einen Zeiger mithilfe der Syntax definieren
var variable_name *type
Das Sternchen (*) stellt dar, dass die Variable ein Zeiger ist. Sie werden mehr verstehen, wenn Sie das folgende Programm ausfรผhren
package main
import "fmt"
func main() {
//Create an integer variable a with value 20
a := 20
//Create a pointer variable b and assigned the address of a
var b *int = &a
//print address of a(&a) and value of a
fmt.Println("Address of a:",&a)
fmt.Println("Value of a:",a)
//print b which contains the memory address of a i.e. &a
fmt.Println("Address of pointer b:",b)
//*b prints the value in memory address which b contains i.e. the value of a
fmt.Println("Value of pointer b",*b)
//increment the value of variable a using the variable b
*b = *b+1
//prints the new value using a and *b
fmt.Println("Value of pointer b",*b)
fmt.Println("Value of a:",a)}
Die Ausgabe wird sein
Address of a: 0x416020 Value of a: 20 Address of pointer b: 0x416020 Value of pointer b 20 Value of pointer b 21 Value of a: 21
Strukturen
Eine Struktur ist ein benutzerdefinierter Datentyp, der selbst ein weiteres Element desselben oder eines anderen Typs enthรคlt.
Die Verwendung einer Struktur ist ein zweistufiger Prozess.
Erstellen (deklarieren) Sie zunรคchst einen Strukturtyp
Zweitens erstellen Sie Variablen dieses Typs, um Werte zu speichern.
Strukturen werden hauptsรคchlich verwendet, wenn Sie zusammengehรถrige Daten zusammen speichern mรถchten.
Betrachten Sie eine Mitarbeiterinformation mit Name, Alter und Adresse. Sie kรถnnen dies auf zwei Arten handhaben
Erstellen Sie drei Arrays โ ein Array speichert die Namen der Mitarbeiter, eines speichert das Alter und das dritte speichert das Alter.
Deklarieren Sie einen Strukturtyp mit drei Feldern: Name, Adresse und Alter. Erstellen Sie ein Array dieses Strukturtyps, wobei jedes Element ein Strukturobjekt mit Namen, Adresse und Alter ist.
Der erste Ansatz ist nicht effizient. In solchen Szenarien sind Strukturen praktischer.
Die Syntax zum Deklarieren einer Struktur lautet
type structname struct {
variable_1 variable_1_type
variable_2 variable_2_type
variable_n variable_n_type
}
Ein Beispiel fรผr eine Strukturdeklaration ist
type emp struct {
name string
address string
age int
}
Hier wird ein neuer benutzerdefinierter Typ namens emp erstellt. Jetzt kรถnnen Sie mithilfe der Syntax Variablen vom Typ emp erstellen
var variable_name struct_name
Ein Beispiel ist
var empdata1 emp
Sie kรถnnen Werte fรผr empdata1 als festlegen
empdata1.name = "John" empdata1.address = "Street-1, Bangalore" empdata1.age = 30
Sie kรถnnen auch eine Strukturvariable erstellen und Werte zuweisen
empdata2 := emp{"Raj", "Building-1, Delhi", 25}
Hier mรผssen Sie die Reihenfolge der Elemente einhalten. Raj wird dem Namen, dem nรคchsten Element der Adressierung und dem letzten dem Alter zugeordnet.
Fรผhren Sie den folgenden Code aus
package main
import "fmt"
//declared the structure named emp
type emp struct {
name string
address string
age int
}
//function which accepts variable of emp type and prints name property
func display(e emp) {
fmt.Println(e.name)
}
func main() {
// declares a variable, empdata1, of the type emp
var empdata1 emp
//assign values to members of empdata1
empdata1.name = "John"
empdata1.address = "Street-1, London"
empdata1.age = 30
//declares and assign values to variable empdata2 of type emp
empdata2 := emp{"Raj", "Building-1, Paris", 25}
//prints the member name of empdata1 and empdata2 using display function
display(empdata1)
display(empdata2)
}
Ausgang
John Raj
Methoden (keine Funktionen)
Eine Methode ist eine Funktion mit einem Empfรคngerargument. ArchiTechnisch gesehen steht es zwischen dem Schlรผsselwort func und dem Methodennamen. Die Syntax einer Methode ist
func (variable variabletype) methodName(parameter1 paramether1type) {
}
Konvertieren wir das obige Beispielprogramm so, dass es Methoden anstelle von Funktionen verwendet.
package main
import "fmt"
//declared the structure named emp
type emp struct {
name string
address string
age int
}
//Declaring a function with receiver of the type emp
func(e emp) display() {
fmt.Println(e.name)
}
func main() {
//declaring a variable of type emp
var empdata1 emp
//Assign values to members
empdata1.name = "John"
empdata1.address = "Street-1, Lodon"
empdata1.age = 30
//declaring a variable of type emp and assign values to members
empdata2 := emp {
"Raj", "Building-1, Paris", 25}
//Invoking the method using the receiver of the type emp
// syntax is variable.methodname()
empdata1.display()
empdata2.display()
}
Go ist keine objektorientierte Sprache und kennt kein Klassenkonzept. Methoden vermitteln einen Eindruck davon, was Sie in objektorientierten Programmen tun, in denen die Funktionen einer Klasse mithilfe der Syntax objektname.funktionsname() aufgerufen werden.
Nebenlรคufigkeit
Go unterstรผtzt die gleichzeitige Ausfรผhrung von Aufgaben. Das bedeutet, dass Go mehrere Aufgaben gleichzeitig ausfรผhren kann. Das unterscheidet sich vom Konzept der Parallelitรคt. Bei der Parallelitรคt wird eine Aufgabe in kleine Unteraufgaben aufgeteilt und parallel ausgefรผhrt. Bei der Gleichzeitigkeit werden jedoch mehrere Aufgaben gleichzeitig ausgefรผhrt. Gleichzeitigkeit wird in Go durch Goroutinen und Kanรคle erreicht.
Goroutinen
Eine Goroutine ist eine Funktion, die gleichzeitig mit anderen Funktionen ausgefรผhrt werden kann. Wenn eine Funktion aufgerufen wird, wird die Kontrolle normalerweise an die aufgerufene Funktion รผbertragen, und sobald die Ausfรผhrung abgeschlossen ist, geht die Kontrolle an die aufrufende Funktion zurรผck. Die aufrufende Funktion setzt dann ihre Ausfรผhrung fort. Die aufrufende Funktion wartet darauf, dass die aufgerufene Funktion die Ausfรผhrung abschlieรt, bevor sie mit den restlichen Anweisungen fortfรคhrt.
Im Fall von Goroutine wartet die aufrufende Funktion jedoch nicht darauf, dass die Ausfรผhrung der aufgerufenen Funktion abgeschlossen ist. Die Ausfรผhrung wird mit den nรคchsten Anweisungen fortgesetzt. Sie kรถnnen mehrere Goroutinen in einem Programm haben.
Auรerdem wird das Hauptprogramm beendet, sobald die Ausfรผhrung seiner Anweisungen abgeschlossen ist, und es wartet nicht auf den Abschluss der aufgerufenen Goroutinen.
Goroutine wird mit dem Schlรผsselwort go aufgerufen, gefolgt von einem Funktionsaufruf.
Beispiel
go add(x,y)
Mit den folgenden Golang-Beispielen werden Sie Goroutinen verstehen. Fรผhren Sie das folgende Programm aus
package main
import "fmt"
func display() {
for i:=0; i<5; i++ {
fmt.Println("In display")
}
}
func main() {
//invoking the goroutine display()
go display()
//The main() continues without waiting for display()
for i:=0; i<5; i++ {
fmt.Println("In main")
}
}
Die Ausgabe wird sein
In main In main In main In main In main
Hier hat das Hauptprogramm die Ausfรผhrung bereits abgeschlossen, bevor die Goroutine gestartet wurde. display() ist eine Goroutine, die mithilfe der Syntax aufgerufen wird
go function_name(parameter list)
Im obigen Code wartet main() nicht auf den Abschluss von display(), und main() hat seine Ausfรผhrung abgeschlossen, bevor display() seinen Code ausgefรผhrt hat. Die print-Anweisung in display() wurde also nicht gedruckt.
Jetzt รคndern wir das Programm so, dass es auch die Anweisungen von display() ausgibt. Wir fรผgen eine Zeitverzรถgerung von 2 Sekunden in der for-Schleife von main() und eine Verzรถgerung von 1 Sekunde in der for-Schleife von display() hinzu.
package main
import "fmt"
import "time"
func display() {
for i:=0; i<5; i++ {
time.Sleep(1 * time.Second)
fmt.Println("In display")
}
}
func main() {
//invoking the goroutine display()
go display()
for i:=0; i<5; i++ {
time.Sleep(2 * time.Second)
fmt.Println("In main")
}
}
Die Ausgabe wird einigermaรen รคhnlich sein
In display In main In display In display In main In display In display In main In main In main
Hier kรถnnen Sie sehen, dass beide Schleifen aufgrund der gleichzeitigen Ausfรผhrung รผberlappend ausgefรผhrt werden.
Kanรคle
Kanรคle sind eine Mรถglichkeit fรผr Funktionen, miteinander zu kommunizieren. Man kann es sich als ein Medium vorstellen, auf dem eine Routine Daten platziert und von einer anderen Routine auf dem Golang-Server darauf zugegriffen wird.
Mit der Syntax kann ein Kanal deklariert werden
channel_variable := make(chan datatype)
Ejemplo:
ch := make(chan int)
Mithilfe der Syntax kรถnnen Sie Daten an einen Kanal senden
channel_variable <- variable_name
Beispiel
ch <- x
Mithilfe der Syntax kรถnnen Sie Daten von einem Kanal empfangen
variable_name := <- channel_variable
Beispiel
y := <- ch
In den obigen Go-Sprachbeispielen fรผr Goroutine haben Sie gesehen, dass das Hauptprogramm nicht auf die Goroutine wartet. Dies ist jedoch nicht der Fall, wenn es um Kanรคle geht. Angenommen, wenn eine Goroutine Daten an den Kanal sendet, wartet main() auf die Anweisung, die Kanaldaten empfรคngt, bis sie die Daten erhรคlt.
Sie werden dies in den folgenden Go-Sprachbeispielen sehen. Schreiben Sie zunรคchst eine normale Goroutine und sehen Sie sich das Verhalten an. รndern Sie dann das Programm, um Kanรคle zu verwenden, und sehen Sie sich das Verhalten an.
Fรผhren Sie das folgende Programm aus
package main
import "fmt"
import "time"
func display() {
time.Sleep(5 * time.Second)
fmt.Println("Inside display()")
}
func main() {
go display()
fmt.Println("Inside main()")
}
Die Ausgabe wird sein
Inside main()
main() beendete die Ausfรผhrung und wurde beendet, bevor die Goroutine ausgefรผhrt wurde. Der Druck innerhalb von display() wurde also nicht ausgefรผhrt.
รndern Sie nun das obige Programm, um Kanรคle zu verwenden, und sehen Sie sich das Verhalten an.
package main
import "fmt"
import "time"
func display(ch chan int) {
time.Sleep(5 * time.Second)
fmt.Println("Inside display()")
ch <- 1234
}
func main() {
ch := make(chan int)
go display(ch)
x := <-ch
fmt.Println("Inside main()")
fmt.Println("Printing x in main() after taking from channel:",x)
}
Die Ausgabe wird sein
Inside display() Inside main() Printing x in main() after taking from channel: 1234
Was hier passiert, ist, dass main() beim Erreichen von x := <-ch auf Daten auf Kanal ch wartet. display() muss 5 Sekunden warten und dann Daten an den Kanal ch รผbertragen. Beim Empfang der Daten vom Kanal wird main() entsperrt und setzt seine Ausfรผhrung fort.
Der Absender, der Daten an den Kanal sendet, kann die Empfรคnger darรผber informieren, dass dem Kanal keine weiteren Daten hinzugefรผgt werden, indem er den Kanal schlieรt. Dies wird hauptsรคchlich verwendet, wenn Sie eine Schleife verwenden, um Daten an einen Kanal zu รผbertragen. Ein Kanal kann mit geschlossen werden
close(channel_name)
Und auf der Empfรคngerseite kann beim Abrufen von Daten vom Kanal mithilfe einer zusรคtzlichen Variablen รผberprรผft werden, ob der Kanal geschlossen ist
variable_name, status := <- channel_variable
Wenn der Status โTrueโ lautet, bedeutet dies, dass Sie Daten vom Kanal empfangen haben. Bei โfalseโ bedeutet dies, dass Sie versuchen, aus einem geschlossenen Kanal zu lesen
Sie kรถnnen auch Kanรคle fรผr die Kommunikation zwischen Goroutinen verwenden. Es mรผssen zwei Goroutinen verwendet werden โ eine sendet Daten an den Kanal und die andere empfรคngt die Daten vom Kanal. Siehe das folgende Programm
package main
import "fmt"
import "time"
//This subroutine pushes numbers 0 to 9 to the channel and closes the channel
func add_to_channel(ch chan int) {
fmt.Println("Send data")
for i:=0; i<10; i++ {
ch <- i //pushing data to channel
}
close(ch) //closing the channel
}
//This subroutine fetches data from the channel and prints it.
func fetch_from_channel(ch chan int) {
fmt.Println("Read data")
for {
//fetch data from channel
x, flag := <- ch
//flag is true if data is received from the channel
//flag is false when the channel is closed
if flag == true {
fmt.Println(x)
}else{
fmt.Println("Empty channel")
break
}
}
}
func main() {
//creating a channel variable to transport integer values
ch := make(chan int)
//invoking the subroutines to add and fetch from the channel
//These routines execute simultaneously
go add_to_channel(ch)
go fetch_from_channel(ch)
//delay is to prevent the exiting of main() before goroutines finish
time.Sleep(5 * time.Second)
fmt.Println("Inside main()")
}
Hier gibt es 2 Unterprogramme, eines schiebt Daten in den Kanal und das andere druckt Daten in den Kanal. Die Funktion add_to_channel addiert die Zahlen von 0 bis 9 und schlieรt den Kanal. Gleichzeitig wartet die Funktion fetch_from_channel
x, flag := <- ch und sobald die Daten verfรผgbar sind, werden die Daten gedruckt. Es wird beendet, sobald das Flag falsch ist, was bedeutet, dass der Kanal geschlossen ist.
Das Warten in main() soll verhindern, dass main() beendet wird, bis die Goroutinen die Ausfรผhrung abgeschlossen haben.
Fรผhren Sie den Code aus und sehen Sie sich die Ausgabe als an
Read data Send data 0 1 2 3 4 5 6 7 8 9 Empty channel Inside main()
Auswรคhlen
Select kann als Switch-Anweisung betrachtet werden, die auf Kanรคlen funktioniert. Hier sind die Case-Anweisungen eine Kanaloperation. Normalerweise wird jede Case-Anweisung aus dem Kanal gelesen. Wenn einer der Fรคlle bereit ist (der Kanal wird gelesen), wird die mit diesem Fall verknรผpfte Anweisung ausgefรผhrt. Wenn mehrere Fรคlle bereit sind, wird ein zufรคlliger ausgewรคhlt. Sie kรถnnen einen Standardfall haben, der ausgefรผhrt wird, wenn keiner der Fรคlle bereit ist.
Sehen wir uns den folgenden Code an
package main
import "fmt"
import "time"
//push data to channel with a 4 second delay
func data1(ch chan string) {
time.Sleep(4 * time.Second)
ch <- "from data1()"
}
//push data to channel with a 2 second delay
func data2(ch chan string) {
time.Sleep(2 * time.Second)
ch <- "from data2()"
}
func main() {
//creating channel variables for transporting string values
chan1 := make(chan string)
chan2 := make(chan string)
//invoking the subroutines with channel variables
go data1(chan1)
go data2(chan2)
//Both case statements wait for data in the chan1 or chan2.
//chan2 gets data first since the delay is only 2 sec in data2().
//So the second case will execute and exits the select block
select {
case x := <-chan1:
fmt.Println(x)
case y := <-chan2:
fmt.Println(y)
}
}
Wenn Sie das obige Programm ausfรผhren, erhalten Sie folgende Ausgabe:
from data2()
Hier wartet die Select-Anweisung darauf, dass Daten in einem der Kanรคle verfรผgbar sind. data2() fรผgt dem Kanal nach einem Ruhezustand von 2 Sekunden Daten hinzu, wodurch der zweite Fall ausgefรผhrt wird.
Fรผgen Sie im selben Programm einen Standardfall zur Auswahl hinzu und sehen Sie sich die Ausgabe an. Wenn kein Fall Daten auf dem Kanal bereithรคlt, wird beim Erreichen des Auswahlblocks der Standardblock ausgefรผhrt, ohne darauf zu warten, dass Daten auf einem Kanal verfรผgbar sind.
package main
import "fmt"
import "time"
//push data to channel with a 4 second delay
func data1(ch chan string) {
time.Sleep(4 * time.Second)
ch <- "from data1()"
}
//push data to channel with a 2 second delay
func data2(ch chan string) {
time.Sleep(2 * time.Second)
ch <- "from data2()"
}
func main() {
//creating channel variables for transporting string values
chan1 := make(chan string)
chan2 := make(chan string)
//invoking the subroutines with channel variables
go data1(chan1)
go data2(chan2)
//Both case statements check for data in chan1 or chan2.
//But data is not available (both routines have a delay of 2 and 4 sec)
//So the default block will be executed without waiting for data in channels.
select {
case x := <-chan1:
fmt.Println(x)
case y := <-chan2:
fmt.Println(y)
default:
fmt.Println("Default case executed")
}
}
Dieses Programm gibt die Ausgabe aus:
Default case executed
Dies liegt daran, dass beim Erreichen des Auswahlblocks kein Kanal Daten zum Lesen hatte. Der Standardfall wird also ausgefรผhrt.
Mutex
Mutex ist die Kurzform fรผr gegenseitigen Ausschluss. Mutex wird verwendet, wenn Sie nicht zulassen mรถchten, dass mehrere Subroutinen gleichzeitig auf eine Ressource zugreifen. Mutex hat zwei Methoden โ Lock und Unlock. Mutex ist im Sync-Paket enthalten. Sie mรผssen also das Sync-Paket importieren. Die Anweisungen, die sich gegenseitig ausschlieรen mรผssen, kรถnnen in mutex.Lock() und mutex.Unlock() platziert werden.
Lassen Sie uns Mutex anhand eines Beispiels lernen, das zรคhlt, wie oft eine Schleife ausgefรผhrt wird. In diesem Programm erwarten wir, dass die Routine die Schleife zehnmal durchlรคuft und die Anzahl als Summe gespeichert wird. Sie rufen diese Routine dreimal auf, sodass die Gesamtanzahl 10 betragen sollte. Die Anzahl wird in einer globalen Variablen count gespeichert.
Zuerst fรผhren Sie das Programm ohne Mutex aus
package main
import "fmt"
import "time"
import "strconv"
import "math/rand"
//declare count variable, which is accessed by all the routine instances
var count = 0
//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
//loop incrementing the count by 10
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
temp := count
temp++
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
count = temp
}
fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}
func main() {
//loop calling the process() 3 times
for i := 1; i < 4; i++ {
go process(i)
}
//delay to wait for the routines to complete
time.Sleep(25 * time.Second)
fmt.Println("Final Count:", count)
}
Sehen Sie das Ergebnis
Count after i=1 Count: 11 Count after i=3 Count: 12 Count after i=2 Count: 13 Final Count: 13
Das Ergebnis kรถnnte bei der Ausfรผhrung anders ausfallen, aber das Endergebnis wird nicht 30 sein.
Was hier passiert, ist, dass 3 Goroutinen versuchen, die in der Variablen count gespeicherte Schleifenanzahl zu erhรถhen. Angenommen, die Anzahl betrรคgt in einem Moment 5 und Goroutine1 erhรถht die Anzahl auf 6. Zu den Hauptschritten gehรถren:
Anzahl in Temp kopieren
Temperatur erhรถhen
Speichertemperatur zurรผck zum Zรคhlen
Angenommen, kurz nach der Ausfรผhrung von Schritt 3 durch goroutine1; Eine andere Goroutine kรถnnte einen alten Wert haben, sagen wir, 3 fรผhrt die oben genannten Schritte aus und speichert 4 zurรผck, was falsch ist. Dies kann durch die Verwendung von Mutex verhindert werden, der dazu fรผhrt, dass andere Routinen warten, wรคhrend eine Routine die Variable bereits verwendet.
Jetzt fรผhren Sie das Programm mit Mutex aus. Hier werden die oben genannten 3 Schritte in einem Mutex ausgefรผhrt.
package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"
//declare a mutex instance
var mu sync.Mutex
//declare count variable, which is accessed by all the routine instances
var count = 0
//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
//loop incrementing the count by 10
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
//lock starts here
mu.Lock()
temp := count
temp++
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
count = temp
//lock ends here
mu.Unlock()
}
fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}
func main() {
//loop calling the process() 3 times
for i := 1; i < 4; i++ {
go process(i)
}
//delay to wait for the routines to complete
time.Sleep(25 * time.Second)
fmt.Println("Final Count:", count)
}
Nun erfolgt die Ausgabe
Count after i=3 Count: 21 Count after i=2 Count: 28 Count after i=1 Count: 30 Final Count: 30
Hier erhalten wir das erwartete Ergebnis als Endausgabe. Denn die Anweisungen zum Lesen, Erhรถhen und Zurรผckschreiben von count werden in einem Mutex ausgefรผhrt.
Fehlerbehandlung
Fehler sind abnormale Zustรคnde wie das Schlieรen einer nicht geรถffneten Datei, das รffnen einer nicht vorhandenen Datei usw. Funktionen geben normalerweise Fehler als letzten Rรผckgabewert zurรผck.
Das folgende Beispiel erklรคrt mehr รผber den Fehler.
package main
import "fmt"
import "os"
//function accepts a filename and tries to open it.
func fileopen(name string) {
f, er := os.Open(name)
//er will be nil if the file exists else it returns an error object
if er != nil {
fmt.Println(er)
return
}else{
fmt.Println("file opened", f.Name())
}
}
func main() {
fileopen("invalid.txt")
}
Der Ausgang wird:
open /invalid.txt: no such file or directory
Hier haben wir versucht, eine nicht vorhandene Datei zu รถffnen, und es wurde der Fehler an die Variable er zurรผckgegeben. Wenn die Datei gรผltig ist, ist der Fehler null
Benutzerdefinierte Fehler
Mit dieser Funktion kรถnnen Sie benutzerdefinierte Fehler erstellen. Dies geschieht durch die Verwendung von New() des Fehlerpakets. Wir werden das obige Programm umschreiben, um benutzerdefinierte Fehler zu nutzen.
Fรผhren Sie das folgende Programm aus
package main
import "fmt"
import "os"
import "errors"
//function accepts a filename and tries to open it.
func fileopen(name string) (string, error) {
f, er := os.Open(name)
//er will be nil if the file exists else it returns an error object
if er != nil {
//created a new error object and returns it
return "", errors.New("Custom error message: File name is wrong")
}else{
return f.Name(),nil
}
}
func main() {
//receives custom error or nil after trying to open the file
filename, error := fileopen("invalid.txt")
if error != nil {
fmt.Println(error)
}else{
fmt.Println("file opened", filename)
}
}
Der Ausgang wird:
Custom error message:File name is wrong
Hier gibt die Funktion โarea()โ die Flรคche eines Quadrats zurรผck. Wenn die Eingabe kleiner als 1 ist, gibt area() eine Fehlermeldung zurรผck.
Dateien lesen
Dateien werden zum Speichern von Daten verwendet. Mit Go kรถnnen wir Daten aus den Dateien lesen
Erstellen Sie zunรคchst in Ihrem aktuellen Verzeichnis eine Datei, data.txt, mit dem folgenden Inhalt.
Line one Line two Line three
Fรผhren Sie nun das folgende Programm aus, um zu sehen, wie der Inhalt der gesamten Datei als Ausgabe ausgegeben wird
package main
import "fmt"
import "io/ioutil"
func main() {
data, err := ioutil.ReadFile("data.txt")
if err != nil {
fmt.Println("File reading error", err)
return
}
fmt.Println("Contents of file:", string(data))
}
Hier die Daten, err := ioutil.ReadFile(โdata.txtโ) liest die Daten und gibt eine Bytesequenz zurรผck. Beim Drucken wird es in das String-Format konvertiert.
Dateien schreiben
Sie werden dies mit einem Programm sehen
package main
import "fmt"
import "os"
func main() {
f, err := os.Create("file1.txt")
if err != nil {
fmt.Println(err)
return
}
l, err := f.WriteString("Write Line one")
if err != nil {
fmt.Println(err)
f.Close()
return
}
fmt.Println(l, "bytes written")
err = f.Close()
if err != nil {
fmt.Println(err)
return
}
}
Hier wird eine Datei erstellt, test.txt. Wenn die Datei bereits vorhanden ist, wird der Inhalt der Datei abgeschnitten. Mit Writeline() wird der Inhalt in die Datei geschrieben. Danach haben Sie die Datei mit Close() geschlossen.
Spickzettel
In diesem Go-Tutorial haben wir Folgendes behandelt:
| Topic | Beschreibung | Syntax |
|---|---|---|
| Grundtypen | Numerisch, Zeichenfolge, Bool | |
| Variablen | Deklarieren Sie Variablen und weisen Sie ihnen Werte zu | var variable_name Typ var Variablenname Typ = Wert var Variablenname1, Variablenname2 = Wert1, Wert2 Variablenname := Wert |
| Konstante | Variablen, deren Wert nach der Zuweisung nicht mehr geรคndert werden kann | const-Variable = Wert |
| Fรผr Schleife | Anweisungen in einer Schleife ausfรผhren. | fรผr initialization_expression; Bewertungsausdruck; iteration_expression{ // eine oder mehrere Anweisung } |
| Ansonsten | Es handelt sich um eine bedingte Anweisung | wenn Bedingung{ // Anweisungen_1 Else {} // Anweisungen_2 } |
| wechseln | Bedingte Anweisung mit mehreren Fรคllen | Ausdruck wechseln { Fallwert_1: Aussagen_1 Fallwert_2: Aussagen_2 Fallwert_n: Statements_n Standard: Statements_default } |
| Feld | Benannte Folge von Elementen desselben Typs mit fester Grรถรe | Arrayname := [Grรถรe] Typ {Wert_0,Wert_1,โฆ,Wert_Grรถรe-1} |
| Slice | Teil oder Segment eines Arrays | var Slice-Name [] Typ = Array-Name [Start: Ende] |
| Funktionen | Anweisungsblock, der eine bestimmte Aufgabe ausfรผhrt | func Funktionsname(Parameter_1 Typ, Parameter_n Typ) return_type { //Aussagen } |
| Angebote | Werden zur Organisation des Codes verwendet. Erhรถht die Lesbarkeit und Wiederverwendbarkeit des Codes | Paketname importieren |
| Verschieben | Verschiebt die Ausfรผhrung einer Funktion, bis die enthaltende Funktion die Ausfรผhrung abgeschlossen hat | Funktionsname (Parameterliste) zurรผckstellen |
| Pointers | Speichert die Speicheradresse einer anderen Variablen. | var Variablenname *Typ |
| Struktur | Benutzerdefinierter Datentyp, der selbst ein weiteres Element desselben oder eines anderen Typs enthรคlt | Typ Strukturname struct { Variable_1 Variable_1_Typ Variable_2 Variable_2_Typ Variable_n Variable_n_Typ } |
| Methoden | Eine Methode ist eine Funktion mit einem Empfรคngerargument | func (Variable Variablentyp) methodName(parameter_list) { } |
| Goroutine | Eine Funktion, die gleichzeitig mit anderen Funktionen ausgefรผhrt werden kann. | go Funktionsname(Parameterliste) |
| Kanal | Mรถglichkeit fรผr Funktionen, miteinander zu kommunizieren. Ein Medium, auf dem eine Routine Daten ablegt und auf das eine andere Routine zugreift. | Erklรคren: ch := make(chan int) Daten an Kanal senden: Kanalvariable <- Variablenname Vom Kanal empfangen: Variablenname := <- Kanalvariable |
| Auswรคhlen | Switch-Anweisung, die auf Kanรคlen funktioniert. Die Case-Anweisungen sind eine Kanaloperation. Wenn ein Kanal mit Daten bereit ist, wird die mit diesem Case verknรผpfte Anweisung ausgefรผhrt. | wรคhlen { Fall x := <-chan1: fmt.Println(x) Fall y := <-chan2: fmt.Println(y) } |
| Mutex | Mutex wird verwendet, wenn Sie nicht zulassen mรถchten, dass mehrere Unterroutinen gleichzeitig auf eine Ressource zugreifen. Mutex verfรผgt รผber zwei Methoden: Sperren und Entsperren | mutex.Lock() //Aussagen mutex.Unlock(). |
| Dateien lesen | Liest die Daten und gibt eine Bytesequenz zurรผck. | Daten, Fehler := ioutil.ReadFile(filename) |
| Datei schreiben | Schreibt Daten in eine Datei | l, err := f.WriteString(text_to_write) |
