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)

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: