Golang-handledning

Vad är Go?

Go (även känt som Golang) är ett programmeringsspråk med öppen källkod som utvecklats av Google. Det är ett statiskt skrivet kompilerat språk. Go stöder samtidig programmering, dvs det tillåter körning av flera processer samtidigt. Detta uppnås med hjälp av kanaler, goroutiner, etc. Go Language har skräpinsamling som själv sköter minneshanteringen och tillåter uppskjuten exekvering av funktioner.

Vi kommer att lära oss alla grunderna i Golang i denna Learn Go Language Tutorial.

Hur man laddar ner och installerar GO

Steg 1) Gå till https://golang.org/dl/. Ladda ner binären för ditt operativsystem.

Steg 2) Double klicka på installationsprogrammet och klicka på Kör.

Steg 3) Klicka på Nästa

Steg 4) Välj installationsmappen och klicka på Nästa.

Steg 5) Klicka på Slutför när installationen är klar.

Steg 6) När installationen är klar kan du verifiera den genom att öppna terminalen och skriva

go version

Detta kommer att visa versionen av go installerad

Ditt First Go-program – Go Hello World!

Skapa en mapp som heter studyGo. I den här Go-språkhandledningen kommer vi att skapa våra go-program i den här mappen. Go-filer skapas med tillägget .gå. Du kan köra Go-program med syntaxen

go run <filename>

Skapa en fil som heter first.go och lägg till koden nedan i den och spara

package main
import ("fmt")

func main() {
	fmt.Println("Hello World! This is my first Go program\n")
}

Navigera till den här mappen i din terminal. Kör programmet med kommandot

gå springa först.gå

Du kan se utskriften

Hello World! This is my first Go program

Låt oss nu diskutera programmet ovan.

huvudpaket – Varje Go Language-program bör börja med ett paketnamn. Go tillåter oss att använda paket i andra go-program och stöder därför återanvändbarhet av kod. Körning av ett Go-program börjar med koden inuti paketet som heter main.

import fmt – importerar paketet fmt. Detta paket implementerar I/O-funktionerna.

func main() – Detta är funktionen från vilken programkörningen börjar. Huvudfunktionen ska alltid placeras i huvudpaketet. Under main() kan du skriva koden inuti { }.

fmt.Println – Detta kommer att skriva ut texten på skärmen med funktionen Println i fmt.

Obs: När du nämner köra/kör koden i avsnitten nedan i denna Go-handledning betyder det att spara koden i en fil med .go-tillägget och köra den med syntaxen

    go run <filename>

Datatyper

Typer (datatyper) representerar typen av värde som lagras i en variabel, typ av värde en funktion returnerar, etc.

Det finns tre grundläggande typer i Go Language

Numeriska typer – Representerar numeriska värden som inkluderar heltal, flyttal och komplexa värden. Olika numeriska typer är:

int8 – 8 bitars signerade heltal.

int16 – 16 bitars signerade heltal.

int32 – 32 bitars signerade heltal.

int64 – 64 bitars signerade heltal.

uint8 – 8-bitars heltal utan tecken.

uint16 – 16-bitars heltal utan tecken.

uint32 – 32-bitars heltal utan tecken.

uint64 – 64-bitars heltal utan tecken.

flytande 32 – 32 bitars flyttal.

flytande 64 – 64 bitars flyttal.

complex64 – har float32 verkliga och imaginära delar.

complex128 – har float32 verkliga och imaginära delar.

Strängtyper – Representerar en sekvens av byte(tecken). Du kan göra olika operationer på strängar som strängsammansättning, extrahera delsträng, etc

booleska typer – Representerar 2 värden, antingen sant eller falskt.

Golang-gränssnitt

Golang-gränssnitt är en samling metodsignaturer som används av en Type för att implementera beteendet hos objekt. Huvudmålet med Golang-gränssnittet är att tillhandahålla metodsignaturer med namn, argument och returtyper. Det är upp till en typ att deklarera och implementera metoden. Ett gränssnitt i Golang kan deklareras med nyckelordet "gränssnitt".

variabler

Variabler pekar på en minnesplats som lagrar något slags värde. Typparametern (i syntaxen nedan) representerar den typ av värde som kan lagras i minnesplatsen.

Variabel kan deklareras med hjälp av syntaxen

    var <variable_name> <type>

När du deklarerar en variabel av en typ kan du tilldela variabeln till vilket värde som helst av den typen.

Du kan också ge ett initialvärde till en variabel under själva deklarationen med hjälp av

    var <variable_name> <type> = <value>

Om du deklarerar variabeln med ett initialt värde, Go och härleda typen av variabel från den typ av värde som tilldelats. Så du kan utelämna typen under deklarationen med hjälp av syntaxen

    var <variable_name> = <value>

Du kan också deklarera flera variabler med syntaxen

    var <variable_name1>, <variable_name2>  = <value1>, <value2>

Nedanstående program i denna Go-handledning har några Golang-exempel på variabeldeklarationer

 
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)
}

Resultatet blir

x: 3
y: 20
z: 50
i and j: 100 hello

Go Language ger också ett enkelt sätt att deklarera variablerna med värde genom att utelämna nyckelordet var

    <variable_name> := <value>

Observera att du använde := istället för =. Du kan inte använda := bara för att tilldela ett värde till en variabel som redan är deklarerad. := används för att deklarera och tilldela värde.

Skapa en fil som heter assign.go med följande kod

package main
import ("fmt")

func main() {
	a := 20
	fmt.Println(a)

	//gives error since a is already declared
	a := 30
	fmt.Println(a)
}

Kör go run assign.go för att se resultatet som

./assign.go:7:4: no new variables on left side of :=		

Variabler som deklareras utan ett initialt värde kommer att ha 0 för numeriska typer, false för booleska och tom sträng för strängar

Konstant

Konstanta variabler är de variabler vars värde inte kan ändras när de väl har tilldelats. En konstant i Go programmeringsspråk deklareras genom att använda nyckelordet "const"

Skapa en fil som heter constant.go och med följande kod

package main
import ("fmt")

func main() {
	const b =10
	fmt.Println(b)
	b = 30
	fmt.Println(b)
}

Kör go run constant.go för att se resultatet som

.constant.go:7:4: cannot assign to b

För loopexempel

Slingor används för att exekvera ett block av satser upprepade gånger baserat på ett villkor. De flesta av programmeringsspråken tillhandahåller 3 typer av loopar – för, medan, do while. Men programmeringsspråket Go stöder endast för loop.

Syntaxen för en Golang för loop är

for initialisation_expression; evaluation_expression; iteration_expression{
   // one or more statement
}

Initialiseringsuttrycket exekveras först (och endast en gång) i Golang for loop.

Sedan utvärderas evaluation_expression och om det är sant exekveras koden inuti blocket.

Iteration_expression id exekveras och evaluation_expression utvärderas igen. Om det är sant exekveras satsblocket igen. Detta kommer att fortsätta tills evaluation_expression blir falskt.

Kopiera programmet nedan till en fil och kör det för att se Golang för looputskriftsnummer från 1 till 5

package main
import "fmt"

func main() {  
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
    }
}

Output är

1
2
3
4
5

Om annat

Om annat är ett villkorligt uttalande. Synaxen är

if condition{
// statements_1
}else{
// statements_2
}

Här utvärderas villkoret och om det är sant kommer statements_1 att exekveras annars kommer statements_2 att exekveras.

Du kan använda if-satsen utan annat också. Du kan också ha kedjade if else-uttalanden. Nedanstående program kommer att förklara mer om annat.

Kör programmet nedan. Den kontrollerar om ett tal, x, är mindre än 10. Om så är fallet kommer det att skriva ut "x är mindre än 10"

package main
import "fmt"

func main() {  
    var x = 50
    if x < 10 {
        //Executes if x < 10
        fmt.Println("x is less than 10")
    } 
}

Eftersom värdet på x här är större än 10 kommer inte satsen inuti if-blocket att köras.

Se nu programmet nedan. I den här guiden för programmeringsspråket Go har vi ett annat block som kommer att köras om utvärderingen misslyckas.

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")
    }
}

Detta program kommer att ge dig utdata

x is greater than or equals 10

Nu i denna Go-handledning kommer vi att se ett program med flera if else-block (kedjade om annat). Utför Go-exemplet nedan. Den kontrollerar om ett tal är mindre än 10 eller är mellan 10-90 eller större än 90.

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")
    }
}

Här kontrollerar först if-villkoret om x är mindre än 10 och inte. Så det kontrollerar nästa villkor (annat om) om det är mellan 10 och 90, vilket också är falskt. Så den exekverar sedan blocket under else-sektionen som ger utdata

x is greater than 90

Växla

Switch är ett annat villkorligt uttalande. Switch-satser utvärderar ett uttryck och resultatet jämförs med en uppsättning tillgängliga värden (fall). När en matchning har hittats exekveras uttalanden som är associerade med matchningen (casefallet). Om ingen matchning hittas kommer ingenting att exekveras. Du kan också lägga till ett standardfall för växling som kommer att köras om inga andra matchningar hittas. Syntaxen för switchen är

switch expression {
    case value_1:
        statements_1
    case value_2:
        statements_2
    case value_n:
        statements_n
    default:
        statements_default
    }

Här jämförs uttryckets värde mot värdena i varje enskilt fall. När en matchning har hittats exekveras de uttalanden som är associerade med det fallet. Om ingen matchning hittas exekveras satserna under standardavsnittet.

Kör programmet nedan

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")
    }
}

Du kommer att få utdata som

Sum is 3		

Ändra värdet på a och b till 3 så blir resultatet

Printing default

Du kan också ha flera värden i ett fall genom att separera dem med ett kommatecken.

arrayer

Array representerar en fast storlek, namngiven sekvens av element av samma typ. Du kan inte ha en array som innehåller både heltal och tecken. Du kan inte ändra storleken på en array när du väl har definierat storleken.

Syntaxen för att deklarera en array är

var arrayname [size] type

Varje matriselement kan tilldelas värde med hjälp av syntaxen

arrayname [index] = value

Arrayindex börjar från 0 till storlek-1.

Du kan tilldela värden till matriselement under deklarationen med hjälp av syntaxen

arrayname := [size] type {value_0,value_1,…,value_size-1} 

Du kan också ignorera storleksparametern medan du deklarerar arrayen med värden genom att ersätta storlek med . och kompilatorn kommer att hitta längden från antalet värden. Syntax är

arrayname :=  […] type {value_0,value_1,…,value_size-1}

Du kan hitta längden på arrayen genom att använda syntaxen

len(arrayname)

Utför Go-exemplet nedan för att förstå arrayen

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]) 
}

Produktion

Two
3
[One Two Three]
[1 2 3 4 5]
5

Golang Slice and Append-funktion

En skiva är en del eller ett segment av en array. Eller så är det en vy eller en delvy av en underliggande array som den pekar på. Du kan komma åt elementen i en skiva med hjälp av skivans namn och indexnummer precis som du gör i en array. Du kan inte ändra längden på en array, men du kan ändra storleken på en skiva.

Innehållet i en skiva är faktiskt pekarna till elementen i en array. Det betyder om du ändrar något element i en skiva kommer det underliggande arrayinnehållet också att påverkas.

Syntaxen för att skapa ett segment är

var slice_name [] type = array_name[start:end]

Detta kommer att skapa en skiva som heter slice_name från en array som heter array_name med elementen i indexet från början till slut-1.

Nu i denna Golang-handledning kommer vi att köra programmet nedan. Programmet kommer att skapa en skiva från arrayen och skriva ut den. Du kan också se att ändring av innehållet i segmentet kommer att ändra den faktiska arrayen.

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)
}

Detta kommer att skriva ut resultatet som

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]

Det finns vissa funktioner som Golang len, Golang append som du kan använda på skivor

len(slice_name) – returnerar längden på skivan

append(slice_name, value_1, value_2) – Golang append används för att lägga till value_1 och value_2 till ett befintligt segment.

append(slice_nale1,slice_name2...) – lägger till skivnamn2 till skivnamn1

Kör följande program.

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)
}

Resultatet blir

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]

Programmet skapar först 2 skivor och skrev ut dess längd. Sedan satte den en skiva till en annan och satte sedan en sträng till den resulterande skivan.

Funktioner

En funktion representerar ett block av satser som utför en specifik uppgift. En funktionsdeklaration berättar för oss funktionsnamn, returtyp och indataparametrar. Funktionsdefinition representerar koden som finns i funktionen. Syntaxen för att deklarera funktionen är

func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}

Parametrarna och returtyperna är valfria. Du kan också returnera flera värden från en funktion.

Nu i denna Golang-handledning, låt oss köra följande Golang-exempel. Funktionen calc här accepterar 2 tal och utför addition och subtraktion och returnerar båda värdena.

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) 
}

Resultatet blir

Sum 25
Diff 5

Paket

Paket används för att organisera koden. I ett stort projekt är det inte möjligt att skriva kod i en enda fil. Go programmeringsspråk låter oss organisera koden under olika paket. Detta ökar kodläsbarheten och återanvändbarheten. Ett körbart Go-program bör innehålla ett paket med namnet main och programkörningen startar från funktionen som heter main. Du kan importera andra paket i vårt program med hjälp av syntaxen

import package_name

Vi kommer att se och diskutera i denna Golang-handledning, hur man skapar och använder paket i följande Golang-exempel.

Steg 1) Skapa en fil som heter package_example.go och lägg till koden nedan

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) 
}

I programmet ovan finns fmt ett paket som Go-programmeringsspråket tillhandahåller oss främst för I/O-ändamål. Du kan också se ett paket som heter beräkning. Inuti main() kan du se en stegsumma := beräkning.Do_add(x,y). Det betyder att du anropar funktionen Do_add från paketberäkning.

Steg 2) Först bör du skapa paketberäkningen i en mapp med samma namn under src-mappen på vägen. Den installerade sökvägen för go kan hittas från PATH-variabeln.

För mac, hitta sökvägen genom att köra echo $PATH

Så sökvägen är /usr/local/go

För Windows, hitta sökvägen genom att köra echo %GOROOT%

Här är sökvägen C:\Go\

Steg 3) Navigera till mappen src (/usr/local/go/src för mac och C:\Go\src för Windows). Nu från koden är paketnamnet beräkning. Go kräver att paketet ska placeras i en katalog med samma namn under src-katalogen. Skapa en katalog som heter beräkning i src-mappen.

Steg 4) Skapa en fil som heter calc.go (Du kan ge vilket namn som helst, men paketnamnet i koden spelar roll. Här ska det vara beräkning) i beräkningskatalogen och lägg till koden nedan

package calculation
  
func Do_add(num1 int, num2 int)(int) {
    sum := num1 + num2
    return sum
}

Steg 5) Kör kommandot go install från beräkningskatalogen som kommer att kompilera calc.go.

Steg 6) Gå nu tillbaka till package_example.go och kör go run package_example.go. Utgången blir summa 25.

Observera att namnet på funktionen Do_add börjar med en stor bokstav. Detta beror på att i Go om funktionsnamnet börjar med en stor bokstav betyder det att andra program kan se (åtkomst) det annars kan andra program inte komma åt det. Om funktionsnamnet var do_add , skulle du ha fått felet

kan inte referera till oexporterad namnberäkning.beräkning.

Defer och stapling defers

Defer-satser används för att skjuta upp exekveringen av ett funktionsanrop tills funktionen som innehåller defer-satsen slutför exekveringen.

Låt oss lära oss detta med ett exempel:

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()")
}

Resultatet blir

Inside the main()
Inside the sample()

Här skjuts exekveringen av sample() upp tills exekveringen av den omslutande funktionen(main()) är klar.

Stacking defer använder flera defer-satser. Anta att du har flera defer-satser i en funktion. Go placerar alla uppskjutna funktionsanrop i en stack, och när den omslutande funktionen återvänder, exekveras de staplade funktionerna i Last In First Out (LIFO) order. Du kan se detta i exemplet nedan.

Kör koden nedan

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)
}

Resultatet blir

4
3
2
1			

Här exekveras först koden inuti main() och sedan exekveras de uppskjutna funktionsanropen i omvänd ordning, dvs 4, 3,2,1.

Pekare

Innan vi förklarar tips, låt oss först diskutera '&'-operatorn. Operatorn '&' används för att få adressen till en variabel. Det betyder att '&a' kommer att skriva ut minnesadressen för variabel a.

I den här Golang-handledningen kommer vi att köra programmet nedan för att visa värdet på en variabel och adressen till den variabeln

package main
import "fmt"

func main() {
	a := 20
	fmt.Println("Address:",&a)
	fmt.Println("Value:",a)
}

Resultatet blir

Address: 0xc000078008
Value: 20

En pekarvariabel lagrar minnesadressen för en annan variabel. Du kan definiera en pekare med hjälp av syntaxen

	var variable_name *type

Asterisken(*) representerar variabeln är en pekare. Du kommer att förstå mer genom att köra programmet nedan

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)}

Resultatet blir

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

Strukturer

En struktur är en användardefinierad datatyp som i sig innehåller ytterligare ett element av samma eller annan typ.

Att använda en struktur är en process i två steg.

Skapa (deklarera) först en strukturtyp

För det andra, skapa variabler av den typen för att lagra värden.

Strukturer används främst när du vill lagra relaterad data tillsammans.

Tänk på en del av anställd information som har namn, ålder och adress. Du kan hantera detta på 2 sätt

Skapa 3 arrayer – en array lagrar namnen på anställda, en lagrar ålder och den tredje lagrar ålder.

Deklarera en strukturtyp med 3 fält-namn, adress och ålder. Skapa en array av den strukturtypen där varje element är ett strukturobjekt med namn, adress och ålder.

Det första tillvägagångssättet är inte effektivt. I den här typen av scenarier är strukturer mer bekväma.

Syntaxen för att deklarera en struktur är

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Ett exempel på en strukturdeklaration är

type emp struct {
    name string
    address string
    age int
}

Här skapas en ny användardefinierad typ som heter emp. Nu kan du skapa variabler av typen emp med hjälp av syntaxen

	var variable_name struct_name

Ett exempel är

var empdata1 emp 

Du kan ställa in värden för empdata1 som

empdata1.name = "John"
	empdata1.address = "Street-1, Bangalore"
	empdata1.age = 30

Du kan också skapa en strukturvariabel och tilldela värden genom

empdata2 := emp{"Raj", "Building-1, Delhi", 25}

Här måste du behålla ordningen på elementen. Raj kommer att mappas till namn, nästa element till adress och det sista att åldras.

Kör koden nedan

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)
}

Produktion

John
Raj

Metoder (inte funktioner)

En metod är en funktion med ett mottagarargument. Archirent tekniskt står det mellan nyckelordet func och metodnamnet. Syntaxen för en metod är

func (variable variabletype) methodName(parameter1 paramether1type) {  
}

Låt oss konvertera ovanstående exempelprogram till att använda metoder istället för funktion.

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 är inte ett objektorienterat språk och det har inte begreppet klass. Metoder ger en känsla av vad du gör i objektorienterade program där funktionerna i en klass anropas med hjälp av syntaxen objektnamn.funktionsnamn()

samtidighet

Go stöder samtidig utförande av uppgifter. Det betyder att Go kan utföra flera uppgifter samtidigt. Det skiljer sig från begreppet parallellism. I parallellism delas en uppgift upp i små deluppgifter och utförs parallellt. Men samtidigt utförs flera uppgifter samtidigt. Samtidighet uppnås i Go med Goroutines och Channels.

Goroutiner

En goroutin är en funktion som kan köras samtidigt med andra funktioner. Vanligtvis när en funktion anropas överförs kontrollen till den anropade funktionen, och när dess slutförda exekveringskontroll återgår till den anropande funktionen. Den anropande funktionen fortsätter sedan att utföras. Den anropande funktionen väntar på att den anropade funktionen slutför exekveringen innan den fortsätter med resten av satserna.

Men i fallet med goroutine, kommer den anropande funktionen inte att vänta på att exekveringen av den anropade funktionen ska slutföras. Det kommer att fortsätta att köras med nästa uttalanden. Du kan ha flera goroutiner i ett program.

Dessutom kommer huvudprogrammet att avslutas när det slutfört exekveringen av sina uttalanden och det kommer inte att vänta på slutförandet av de anropade goroutinerna.

Goroutine anropas med nyckelordet go följt av ett funktionsanrop.

Exempelvis

go add(x,y)

Du kommer att förstå goroutiner med Golang-exemplen nedan. Kör programmet nedan

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")
	}
}

Resultatet blir

In main
In main
In main
In main
In main

Här avslutade huvudprogrammet exekveringen redan innan goroutinen startade. Display() är en goroutin som anropas med hjälp av syntaxen

go function_name(parameter list)

I ovanstående kod väntar main() inte på att display() ska slutföras, och main() slutförde sin körning innan display() exekverade sin kod. Så print-satsen inuti display() skrivs inte ut.

Nu modifierar vi programmet för att även skriva ut satserna från display(). Vi lägger till en tidsfördröjning på 2 sek i for-slingan i main() och en 1 sek fördröjning i for-slingan på display().

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")
	}
}

Utgången kommer att vara något liknande

In display
In main
In display
In display
In main
In display
In display
In main
In main
In main

Här kan du se att båda looparna exekveras på ett överlappande sätt på grund av den samtidiga exekveringen.

Kanaler

Kanaler är ett sätt för funktioner att kommunicera med varandra. Det kan ses som ett medium där en rutin placerar data och nås av en annan rutin i Golang-servern.

En kanal kan deklareras med syntaxen

channel_variable := make(chan datatype)

Exempelvis:

	ch := make(chan int)

Du kan skicka data till en kanal med hjälp av syntaxen

channel_variable <- variable_name

Exempelvis

    ch <- x

Du kan ta emot data från en kanal med hjälp av syntaxen

    variable_name := <- channel_variable

Exempelvis

   y := <- ch

I ovanstående Go-språkexempel på goroutine har du sett att huvudprogrammet inte väntar på goroutinen. Men så är det inte när kanaler är inblandade. Anta att om en goroutin skjuter data till kanal, kommer main() att vänta på satsen som tar emot kanaldata tills den får data.

Du kommer att se detta i exempel på Go-språk nedan. Skriv först en normal goroutin och se beteendet. Ändra sedan programmet för att använda kanaler och se beteendet.

Kör programmet nedan

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()")
}

Resultatet blir

Inside main()

Main() avslutade exekveringen och avslutade innan goroutinen kördes. Så utskriften inuti display() kördes inte.

Ändra nu programmet ovan för att använda kanaler och se beteendet.

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)
}

Resultatet blir

Inside display()
Inside main()
Printing x in main() after taking from channel: 1234

Här vad som händer är main() när man når x := <-ch väntar på data på kanal ch. Displayen() har en väntetid på 5 sekunder och skickar sedan data till kanalen ch. Main() för att ta emot data från kanalen avblockeras och fortsätter dess exekvering.

Avsändaren som skickar data till kanalen kan informera mottagarna att ingen mer data kommer att läggas till kanalen genom att stänga kanalen. Detta används främst när du använder en loop för att skicka data till en kanal. En kanal kan stängas med

close(channel_name)

Och i mottagaränden är det möjligt att kontrollera om kanalen är stängd med hjälp av en extra variabel medan data hämtas från kanalen med

variable_name, status := <- channel_variable

Om statusen är True betyder det att du fått data från kanalen. Om falskt betyder det att du försöker läsa från en stängd kanal

Du kan också använda kanaler för kommunikation mellan goroutiner. Behöver använda 2 goroutiner – en skickar data till kanalen och andra tar emot data från kanalen. Se programmet nedan

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()")
}

Här finns det 2 subrutiner en skjuter data till kanalen och andra skriver ut data till kanalen. Funktionen add_to_channel adderar siffrorna från 0 till 9 och stänger kanalen. Samtidigt väntar funktionen hämta_från_kanal kl

x, flagga := <- ch och när data blir tillgängliga skrivs data ut. Den avslutas när flaggan är falsk vilket betyder att kanalen är stängd.

Väntan i main() ges för att förhindra att main() lämnas tills goroutinerna avslutar exekveringen.

Kör koden och se utdata som

Read data
Send data
0
1
2
3
4
5
6
7
8
9
Empty channel
Inside main()

Välja

Select kan ses som en switch-sats som fungerar på kanaler. Här kommer fallutlåtandena att vara en kanaloperation. Vanligtvis kommer varje fall uttalanden att läsas försök från kanalen. När något av fallen är klart (kanalen läses) exekveras uttalandet som är associerat med det ärendet. Om flera fall är klara kommer den att välja ett slumpmässigt. Du kan ha ett standardfall som körs om inget av fallen är klart.

Låt oss se koden nedan

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)
    }
}

Att köra programmet ovan ger resultatet:

from data2()

Här väntar select-satsen på att data ska vara tillgänglig i någon av kanalerna. Data2() lägger till data till kanalen efter en sömn på 2 sekunder vilket gör att det andra fallet körs.

Lägg till ett standardfall till markeringen i samma program och se resultatet. Här, när det väljs block, om inget fall har data redo på kanalen, kommer det att exekvera standardblocket utan att vänta på att data ska vara tillgänglig på någon kanal.

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")
    }
}

Detta program kommer att ge resultatet:

Default case executed			

Detta beror på att när valblocket nådde hade ingen kanal data för läsning. Så standardfallet exekveras.

mutex

Mutex är kortformen för ömsesidig uteslutning. Mutex används när du inte vill tillåta att en resurs ska nås av flera subrutiner samtidigt. Mutex har 2 metoder - Lås och Lås upp. Mutex finns i sync-paketet. Så du måste importera synkroniseringspaketet. De satser som måste utföras ömsesidigt uteslutande kan placeras inuti mutex.Lock() och mutex.Unlock().

Låt oss lära oss mutex med ett exempel som räknar antalet gånger en loop exekveras. I det här programmet förväntar vi oss att rutinen körs loop 10 gånger och räkningen lagras i summa. Du anropar denna rutin 3 gånger så det totala antalet bör vara 30. Antalet lagras i en global variabelräkning.

Först kör du programmet utan mutex

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)
}

Se resultatet

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

Resultatet kan bli annorlunda när du kör det men slutresultatet blir inte 30.

Det som händer här är att 3 goroutiner försöker öka antalet loopar som lagras i det variabla antalet. Anta att antalet vid ett ögonblick är 5 och goroutine1 kommer att öka antalet till 6. Huvudstegen inkluderar

Kopiera räkna till temp

Öka temp

Spara temperaturen tillbaka för att räkna

Antag att strax efter att ha utfört steg 3 av goroutine1; en annan goroutin kan ha ett gammalt värde, säg att 3 gör ovanstående steg och lagrar 4 tillbaka, vilket är fel. Detta kan förhindras genom att använda mutex som gör att andra rutiner väntar när en rutin redan använder variabeln.

Nu kommer du att köra programmet med mutex. Här exekveras de ovan nämnda 3 stegen i en mutex.

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)
}

Nu blir utgången

 Count after i=3 Count: 21
Count after i=2 Count: 28
Count after i=1 Count: 30
Final Count: 30

Här får vi det förväntade resultatet som slutresultat. Eftersom uttalandena läser, inkrementerar och skriver tillbaka räkningen utförs i en mutex.

Felhantering

Fel är onormala tillstånd som att stänga en fil som inte är öppen, öppna en fil som inte finns, etc. Funktioner returnerar vanligtvis fel som det sista returvärdet.

Exemplet nedan förklarar mer om felet.

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")
}

Utgången kommer att vara:

open /invalid.txt: no such file or directory

Här försökte vi öppna en icke-existerande fil, och den returnerade felet till er variabel. Om filen är giltig kommer felet att vara null

Anpassade fel

Med den här funktionen kan du skapa anpassade fel. Detta görs genom att använda New() av ​​felpaketet. Vi kommer att skriva om programmet ovan för att använda anpassade fel.

Kör programmet nedan

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)
    }  
}

Utgången kommer att vara:

Custom error message:File name is wrong

Här returnerar area() arean av en kvadrat. Om inmatningen är mindre än 1 returnerar area() ett felmeddelande.

Läser filer

Filer används för att lagra data. Go låter oss läsa data från filerna

Skapa först en fil, data.txt, i din nuvarande katalog med innehållet nedan.

Line one
Line two
Line three

Kör nu programmet nedan för att se att det skriver ut innehållet i hela filen som utdata

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))
}

Här läser data, err := ioutil.ReadFile(“data.txt”) data och returnerar en bytesekvens. Under utskrift konverteras den till strängformat.

Skriver filer

Du kommer att se detta med ett program

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
    }
}

Här skapas en fil, test.txt. Om filen redan finns trunkeras innehållet i filen. Writeline() används för att skriva innehållet till filen. Efter det stängde du filen med Close().

Fusklapp

I denna Go-handledning täckte vi,

Ämne BESKRIVNING syntax
Grundtyper Numerisk, sträng, bool
variabler Deklarera och tilldela värden till variabler var variabelnamn typ
var variabelnamn typ = värde
var variabelnamn1, variabelnamn2 = värde1, värde2
variabelnamn := värde
Konstant Variabler vars värde inte kan ändras när de väl har tilldelats const variabel = värde
För Loop Kör uttalanden i en loop. för initialiseringsuttryck; evaluation_expression; iteration_expression{
// ett eller flera uttalanden
}
Om annat Det är ett villkorligt uttalande om skick{
// uttalanden_1
} Else {
// uttalanden_2
}
strömbrytare Villkorligt uttalande med flera fall switch expression {
case value_1:
uttalanden_1
case value_2:
uttalanden_2
case value_n:
uttalanden_n
default:
statements_default
}
array Fast storlek med namnet sekvens av element av samma typ arrayname := [size] typ {value_0,value_1,...,value_size-1}
Skiva Del eller segment av en array var slice_name [] typ = array_name[start:slut]
Funktioner Block av uttalanden som utför en specifik uppgift func function_name(parameter_1 typ, parameter_n type) return_type {
//påståenden
}
Paket Används för att organisera koden. Ökar kodläsbarhet och återanvändbarhet importera paket_nam
Skjut upp Dröjer upp exekveringen av en funktion tills den innehållande funktionen avslutar exekveringen defer function_name (parameter_list)
Pekare Lagrar minnesadressen för en annan variabel. var variabelnamn *typ
Structure Användardefinierad datatyp som i sig innehåller ytterligare ett element av samma eller annan typ typ structname struct {
variabel_1 variabel_1_typ
variabel_2 variabel_2_typ
variabel_n variabel_n_typ
}
Metoder En metod är en funktion med ett mottagarargument func (variabel variabeltyp) methodName(parameter_list) {
}
Goroutine En funktion som kan köras samtidigt med andra funktioner. gå funktionsnamn(parameterlista)
Kanal Sätt för funktioner att kommunicera med varandra. Ett medium till vilket en rutin placerar data och nås av en annan rutin. Förklara:
ch := make(chan int)
Skicka data till kanal:
kanalvariabel <- variabelnamn
Ta emot från kanal:
variabelnamn := <- kanalvariabel
Välja Switch statement som fungerar på kanaler. Fallutlåtandena kommer att vara en kanaloperation. När någon av kanalerna är redo med data, exekveras uttalandet som är associerat med det fallet Välj {
fall x := <-chan1:
fmt.Println(x)
fall y := <-chan2:
fmt.Println(y)
}
mutex Mutex används när du inte vill tillåta att en resurs ska nås av flera subrutiner samtidigt. Mutex har 2 metoder - Lås och Lås upp mutex.Lock()
//påståenden
mutex.Unlock().
Läs filer Läser data och returnerar en bytesekvens. Data, fel := ioutil.ReadFile(filnamn)
Skriv fil Skriver data till en fil l, fel := f.WriteString(text_to_write)