Golang-Tutorial: Lernen Sie die Programmiersprache Go für Anfänger

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 die gleichzeitige Programmierung, dh es ermöglicht die gleichzeitige Ausführung mehrerer Prozesseneonormalerweise. Dies wird mithilfe von Kanälen, Goroutinen usw. erreicht. Go Language verfügt über eine Garbage Collection, die selbst die Speicherverwaltung übernimmt 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) Gehen Sie zu https://golang.org/dl/. Laden Sie die Binärdatei für Ihr Betriebssystem herunter.

Schritt 2) Doppelklicken Sie auf das Installationsprogramm und klicken Sie 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 – Stellen Sie numerische Werte dar, einschließlich Ganzzahl, Gleitkomma und Kommaplex 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. die Verkettung von Zeichenfolgen, das 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 folgendem Inhalt:wing 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 mit dem Namen „constant.go“ und folgender Datei:wing 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]) 
}

Output

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 Folgendes auswing

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 ausführenwing Golang-Beispiel. Hier akzeptiert die Funktion calc zwei 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 diskutieren, wie man im Folgenden Pakete erstellt und verwendetwing Golang-Beispiel.

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 für Windows den Pfad, indem Sie echo %GOROOT% ausführen.

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). Aus dem Code wird nun der Paketname berechnet. Go erfordert, dass das Paket in einem gleichnamigen Verzeichnis unter dem src-Verzeichnis abgelegt wird. Erstellen Sie im Ordner src ein Verzeichnis mit dem Namen „calculation“.

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 die Zeiger erklären, wollen wir zunächst den Operator „&“ besprechen. 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)
}

Output

John
Raj

Methoden (keine Funktionen)

Eine Methode ist eine Funktion mit einem Empfängerargument. Architektonisch gesehen liegt 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 kannneonormalerweise. Es unterscheidet sich vom Konzept der Parallelität. Bei der Parallelität wird eine Aufgabe in kleine Teilaufgaben aufgeteilt und parallel ausgeführt. Bei der Parallelität werden jedoch mehrere Aufgaben gleichzeitig ausgeführtneonormalerweise. Parallelität wird in Go mithilfe von Goroutinen und Kanälen 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)

Beispiel:

	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 zwei Unterprogramme: Eines überträgt Daten an den Kanal und das andere druckt Daten an den Kanal. Die Funktion add_to_channel addiert die Zahlen von 2 bis 0 und schließt den Kanal. SimultanneoNormalerweise 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 handelt es sich bei den Case-Anweisungen um eine Kanaloperation. Normalerweise werden alle Case-Anweisungen aus dem Kanal gelesen. Wenn einer der Fälle bereit ist (der Kanal wird gelesen), wird die diesem Fall zugeordnete Anweisung ausgeführt. Wenn mehrere Fälle bereit sind, wird ein zufälliger Fall ausgewählt. Sie können einen Standardfall festlegen, 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 Unterroutinen gleichzeitig auf eine Ressource zugreifen. Mutex verfügt über zwei Methoden: Sperren und Entsperren. Mutex ist im Synchronisierungspaket enthalten. Sie müssen also das Synchronisierungspaket importieren. Die Anweisungen, die gegenseitig ausschließlich ausgeführt werden 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:

Thema 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 einer der Kanäle mit Daten bereit ist, wird die diesem Fall zugeordnete 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)