Golang-opplæring

Hva er Go?

Go (også kjent som Golang) er et åpen kildekode-programmeringsspråk utviklet av Google. Det er et statisk skrevet kompilert språk. Go støtter samtidig programmering, dvs. den tillater å kjøre flere prosesser samtidig. Dette oppnås ved hjelp av kanaler, goroutiner, etc. Go Language har søppelinnsamling som selv gjør minnehåndteringen og tillater utsatt utførelse av funksjoner.

Vi vil lære alt det grunnleggende om Golang i denne Learn Go Language-opplæringen.

Hvordan laste ned og installere GO

Trinn 1) Gå til https://golang.org/dl/. Last ned binær for ditt operativsystem.

Trinn 2) Double klikk på installasjonsprogrammet og klikk Kjør.

Trinn 3) Klikk på Neste

Trinn 4) Velg installasjonsmappen og klikk på Neste.

Trinn 5) Klikk på Fullfør når installasjonen er fullført.

Trinn 6) Når installasjonen er fullført, kan du bekrefte den ved å åpne terminalen og skrive

go version

Dette vil vise versjonen av go installert

Ditt første Go-program – Go Hello World!

Opprett en mappe kalt studyGo. I denne Go-språkopplæringen vil vi lage våre go-programmer i denne mappen. Go-filer opprettes med utvidelsen .gå. Du kan kjøre Go-programmer ved å bruke syntaksen

go run <filename>

Lag en fil kalt first.go og legg til koden nedenfor i den og lagre

package main
import ("fmt")

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

Naviger til denne mappen i terminalen din. Kjør programmet ved å bruke kommandoen

gå løp først.gå

Du kan se utskriften

Hello World! This is my first Go program

La oss nå diskutere programmet ovenfor.

hovedpakke – Hvert Go Language-program bør starte med et pakkenavn. Go lar oss bruke pakker i andre go-programmer og støtter dermed gjenbruk av kode. Kjøring av et Go-program begynner med koden inne i pakken som heter main.

import fmt – importerer pakken fmt. Denne pakken implementerer I/O-funksjonene.

func main() – Dette er funksjonen som programkjøringen starter fra. Hovedfunksjonen skal alltid plasseres i hovedpakken. Under main() kan du skrive koden inne i { }.

fmt.Println – Dette vil skrive ut teksten på skjermen ved hjelp av Println-funksjonen til fmt.

Merk: I delene nedenfor av denne Go-opplæringen, når du nevner kjør/kjør koden, betyr det å lagre koden i en fil med .go-utvidelsen og kjøre den ved å bruke syntaksen

    go run <filename>

Datatyper

Typer (datatyper) representerer typen verdi som er lagret i en variabel, typen verdi en funksjon returnerer, osv.

Det er tre grunnleggende typer i Go Language

Numeriske typer – Representerer numeriske verdier som inkluderer heltall, flyttall og komplekse verdier. Ulike numeriske typer er:

int8 – 8-bits signerte heltall.

int16 – 16-bits signerte heltall.

int32 – 32-bits signerte heltall.

int64 – 64-bits signerte heltall.

uint8 – 8 bit usignerte heltall.

uint16 – 16 bit usignerte heltall.

uint32 – 32 bit usignerte heltall.

uint64 – 64 bit usignerte heltall.

flyt32 – 32-bits flytende kommatall.

flyt64 – 64-bits flytende kommatall.

complex64 – har float32 ekte og imaginære deler.

complex128 – har float32 ekte og imaginære deler.

Strengetyper – Representerer en sekvens av byte (tegn). Du kan gjøre forskjellige operasjoner på strenger som strengsammenkobling, trekke ut understreng osv

boolske typer – Representerer 2 verdier, enten sant eller usant.

Golang-grensesnitt

Golang-grensesnitt er en samling metodesignaturer som brukes av en Type for å implementere oppførselen til objekter. Hovedmålet med Golang-grensesnittet er å gi metodesignaturer med navn, argumenter og returtyper. Det er opp til en Type å deklarere og implementere metoden. Et grensesnitt i Golang kan deklareres ved å bruke søkeordet "grensesnitt".

Variabler

Variabler peker til en minneplassering som lagrer en slags verdi. Typeparameteren (i syntaksen nedenfor) representerer typen verdi som kan lagres i minneplasseringen.

Variabel kan deklareres ved hjelp av syntaksen

    var <variable_name> <type>

Når du erklærer en variabel av en type, kan du tilordne variabelen til en hvilken som helst verdi av den typen.

Du kan også gi en startverdi til en variabel under selve deklarasjonen ved å bruke

    var <variable_name> <type> = <value>

Hvis du erklærer variabelen med en innledende verdi, kan du gå og utlede typen av variabelen fra typen verdi som er tildelt. Så du kan utelate typen under erklæringen ved å bruke syntaksen

    var <variable_name> = <value>

Du kan også deklarere flere variabler med syntaksen

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

Programmet nedenfor i denne Go-opplæringen har noen Golang-eksempler på variabeldeklarasjoner

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

Utgangen vil være

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

Go Language gir også en enkel måte å deklarere variablene med verdi ved å utelate var nøkkelordet ved å bruke

    <variable_name> := <value>

Merk at du brukte := istedenfor =. Du kan ikke bruke := bare for å tilordne en verdi til en variabel som allerede er deklarert. := brukes til å deklarere og tilordne verdi.

Lag en fil kalt assign.go med følgende kode

package main
import ("fmt")

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

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

Utfør go run assign.go for å se resultatet som

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

Variabler deklarert uten en startverdi vil ha 0 for numeriske typer, usann for boolsk og tom streng for strenger

Konstant

Konstante variabler er de variablene hvis verdi ikke kan endres når de først er tildelt. En konstant i Go programmeringsspråk er deklarert ved å bruke nøkkelordet "const"

Lag en fil kalt constant.go og med følgende kode

package main
import ("fmt")

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

Utfør go run constant.go for å se resultatet som

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

For løkkeeksempler

Loops brukes til å utføre en blokk med setninger gjentatte ganger basert på en betingelse. De fleste programmeringsspråkene gir 3 typer løkker - for, while, do while. Men programmeringsspråket Go støtter bare for loop.

Syntaksen til en Golang for loop er

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

Initialiseringsuttrykket utføres først (og bare én gang) i Golang for loop.

Deretter blir evaluation_expression evaluert og hvis det er sant, blir koden inne i blokken utført.

Iteration_expression-ID-en kjøres, og evaluation_expression evalueres på nytt. Hvis det er sant, kjøres setningsblokken igjen. Dette vil fortsette til evaluation_expression blir falsk.

Kopier programmet nedenfor til en fil og kjør den for å se Golang for løkkeutskriftstall fra 1 til 5

package main
import "fmt"

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

Output er

1
2
3
4
5

Hvis ellers

Hvis annet er en betinget erklæring. Synaksen er

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

Her blir tilstanden evaluert, og hvis den er sann vil utsagn_1 bli utført, ellers vil utsagn_2 bli utført.

Du kan bruke if-setning uten annet også. Du kan også ha lenket if else-utsagn. Programmene nedenfor vil forklare mer om hvis annet.

Utfør programmet nedenfor. Den sjekker om et tall, x, er mindre enn 10. I så fall vil den skrive ut "x er mindre enn 10"

package main
import "fmt"

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

Her siden verdien av x er større enn 10, vil ikke setningen i if-blokktilstanden utføres.

Se nå programmet nedenfor. I denne Go-programmeringsspråkopplæringen har vi en annen blokk som vil bli utført ved feil i if-evaluering.

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

Dette programmet vil gi deg utdata

x is greater than or equals 10

Nå i denne Go-opplæringen vil vi se et program med flere if else-blokker (lenket hvis annet). Utfør Go-eksemplet nedenfor. Den sjekker om et tall er mindre enn 10 eller er mellom 10-90 eller større enn 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")
    }
}

Her kontrollerer først if-tilstanden om x er mindre enn 10 og det er den ikke. Så den sjekker den neste betingelsen (eller hvis) om den er mellom 10 og 90, som også er falsk. Så den utfører blokken under else-delen som gir utdata

x is greater than 90

Bytte om

Switch er en annen betinget uttalelse. Switch-setninger evaluerer et uttrykk og resultatet sammenlignes med et sett med tilgjengelige verdier(tilfeller). Når et samsvar er funnet, utføres setningene som er knyttet til den matchen (saken). Hvis ingen treff blir funnet, vil ingenting bli utført. Du kan også legge til et standard tilfelle for å bytte som vil bli utført hvis ingen andre treff blir funnet. Syntaksen til bryteren er

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

Her sammenlignes verdien av uttrykket mot verdiene i hvert enkelt tilfelle. Når et samsvar er funnet, utføres setningene knyttet til den saken. Hvis ingen samsvar blir funnet, utføres setningene under standarddelen.

Utfør programmet nedenfor

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 vil få utgangen som

Sum is 3		

Endre verdien av a og b til 3 og resultatet blir

Printing default

Du kan også ha flere verdier i en sak ved å skille dem med et komma.

arrays

Array representerer en fast størrelse, kalt sekvens av elementer av samme type. Du kan ikke ha en matrise som inneholder både heltall og tegn. Du kan ikke endre størrelsen på en matrise når du først har definert størrelsen.

Syntaksen for å deklarere en matrise er

var arrayname [size] type

Hvert matriseelement kan tildeles verdi ved hjelp av syntaksen

arrayname [index] = value

Array-indeks starter fra 0 til størrelse-1.

Du kan tilordne verdier til matriseelementer under erklæringen ved hjelp av syntaksen

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

Du kan også ignorere størrelsesparameteren mens du erklærer matrisen med verdier ved å erstatte størrelse med ... og kompilatoren vil finne lengden fra antall verdier. Syntaks er

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

Du kan finne lengden på matrisen ved å bruke syntaksen

len(arrayname)

Utfør Go-eksemplet nedenfor for å forstå matrisen

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

Produksjon

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

Golang Slice and Append-funksjon

En skive er en del eller et segment av en matrise. Eller det er en visning eller delvis visning av en underliggende matrise som den peker på. Du kan få tilgang til elementene i en skive ved å bruke skivenavnet og indeksnummeret akkurat som du gjør i en matrise. Du kan ikke endre lengden på en matrise, men du kan endre størrelsen på en skive.

Innholdet i en skive er faktisk pekerne til elementene i en matrise. Det betyr hvis du endrer et element i en skive, vil det underliggende matriseinnholdet også bli påvirket.

Syntaksen for å lage en skive er

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

Dette vil lage en skive som heter slice_name fra en matrise kalt array_name med elementene i indeksen som starter til slutt-1.

Nå i denne Golang-opplæringen vil vi kjøre programmet nedenfor. Programmet vil lage en skive fra matrisen og skrive den ut. Du kan også se at endring av innholdet i stykket vil endre den faktiske matrisen.

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

Dette vil skrive 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 er visse funksjoner som Golang len, Golang append som du kan bruke på skiver

len(slice_name) – returnerer lengden på skiven

tilføy(slice_name, value_1, value_2) – Golang append brukes til å legge til verdi_1 og verdi_2 til en eksisterende skive.

legg til(slice_nale1,slice_name2...) – legger til skivenavn2 til skivenavn1

Kjør følgende 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)
}

Utgangen vil være

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 lager først 2 skiver og skriver ut lengden. Deretter la den en skive til den andre og la deretter en streng til den resulterende skiven.

Funksjoner

En funksjon representerer en blokk med utsagn som utfører en spesifikk oppgave. En funksjonserklæring forteller oss funksjonsnavn, returtype og inngangsparametere. Funksjonsdefinisjon representerer koden i funksjonen. Syntaksen for å deklarere funksjonen er

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

Parametrene og returtypene er valgfrie. Du kan også returnere flere verdier fra en funksjon.

La oss nå i denne Golang-opplæringen kjøre følgende Golang-eksempel. Her vil funksjonen calc akseptere 2 tall og utføre addisjon og subtraksjon og returnerer begge verdiene.

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

Utgangen vil være

Sum 25
Diff 5

Nettsidepakker

Pakker brukes til å organisere koden. I et stort prosjekt er det ikke mulig å skrive kode i en enkelt fil. Go programmeringsspråk lar oss organisere koden under forskjellige pakker. Dette øker kodelesbarheten og gjenbrukbarheten. Et kjørbart Go-program bør inneholde en pakke kalt main og programkjøringen starter fra funksjonen som heter main. Du kan importere andre pakker i programmet vårt ved å bruke syntaksen

import package_name

Vi vil se og diskutere i denne Golang-opplæringen hvordan du oppretter og bruker pakker i følgende Golang-eksempel.

Trinn 1) Opprett en fil kalt package_example.go og legg til koden nedenfor

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 ovenfor er fmt en pakke som Go-programmeringsspråket gir oss hovedsakelig for I/O-formål. Du kan også se en pakke som heter beregning. Inne i main() kan du se en trinnsum := beregning.Do_add(x,y). Det betyr at du påkaller funksjonen Do_add fra pakkeberegning.

Trinn 2) Først bør du lage pakkeberegningen i en mappe med samme navn under src-mappen på farten. Den installerte banen til go finner du fra PATH-variabelen.

For mac, finn banen ved å kjøre echo $PATH

Så banen er /usr/local/go

For Windows, finn banen ved å utføre ekko %GOROOT%

Her er banen C:\Go\

Trinn 3) Naviger til til src-mappen (/usr/local/go/src for mac og C:\Go\src for Windows). Nå fra koden er pakkenavnet beregning. Go krever at pakken skal plasseres i en katalog med samme navn under src-katalogen. Opprett en katalog som heter beregning i src-mappen.

Trinn 4) Lag en fil som heter calc.go (Du kan gi hvilket som helst navn, men pakkenavnet i koden betyr noe. Her skal det være beregning) inne i kalkulasjonskatalogen og legg til koden nedenfor

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

Trinn 5) Kjør kommandoen go install fra kalkulasjonskatalogen som vil kompilere calc.go.

Trinn 6) Gå nå tilbake til package_example.go og kjør go run package_example.go. Utgangen vil være sum 25.

Merk at navnet på funksjonen Do_add starter med stor bokstav. Dette er fordi i Go hvis funksjonsnavnet starter med stor bokstav betyr det at andre programmer kan se (tilgang) det ellers kan ikke andre programmer få tilgang til det. Hvis funksjonsnavnet var do_add , ville du ha fått feilen

kan ikke referere til ueksportert navn calculation.calc..

Defer og stabling defers

Defer-setninger brukes til å utsette utførelsen av et funksjonskall til funksjonen som inneholder defer-setningen fullfører kjøringen.

La oss lære dette med et eksempel:

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

Utgangen vil være

Inside the main()
Inside the sample()

Her blir kjøringen av sample() utsatt til utførelsen av den omsluttende funksjonen(main()) er fullført.

Stacking defer er å bruke flere defer-setninger. Anta at du har flere defer-setninger inne i en funksjon. Go plasserer alle de utsatte funksjonskallene i en stabel, og når den omsluttende funksjonen kommer tilbake, utføres de stablede funksjonene i Last In First Out (LIFO) rekkefølge. Du kan se dette i eksemplet nedenfor.

Utfør koden nedenfor

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

Utgangen vil være

4
3
2
1			

Her kjøres koden inne i main() først, og deretter utføres de utsatte funksjonskallene i omvendt rekkefølge, dvs. 4, 3,2,1.

pekere

Før vi forklarer pekere, la oss først diskutere '&'-operatoren. Operatoren '&' brukes til å få adressen til en variabel. Det betyr at '&a' vil skrive ut minneadressen til variabel a.

I denne Golang-opplæringen vil vi kjøre programmet nedenfor for å vise verdien til en variabel og adressen til den variabelen

package main
import "fmt"

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

Resultatet blir

Address: 0xc000078008
Value: 20

En pekervariabel lagrer minneadressen til en annen variabel. Du kan definere en peker ved å bruke syntaksen

	var variable_name *type

Stjernen(*) representerer variabelen er en peker. Du vil forstå mer ved å kjøre programmet nedenfor

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

Utgangen vil være

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

Structures

En struktur er en brukerdefinert datatype som i seg selv inneholder ett element til av samme eller annen type.

Å bruke en struktur er en 2-trinns prosess.

Først oppretter (erklærer) en strukturtype

For det andre, lag variabler av den typen for å lagre verdier.

Strukturer brukes hovedsakelig når du vil lagre relaterte data sammen.

Tenk på en ansattinformasjon som har navn, alder og adresse. Du kan håndtere dette på 2 måter

Lag 3 arrays – en array lagrer navnene på ansatte, en lagrer alder og den tredje lagrer alder.

Deklarer en strukturtype med 3 felt-navn, adresse og alder. Lag en matrise av den strukturtypen der hvert element er et strukturobjekt med navn, adresse og alder.

Den første tilnærmingen er ikke effektiv. I slike scenarier er strukturer mer praktiske.

Syntaksen for å deklarere en struktur er

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Et eksempel på en strukturdeklarasjon er

type emp struct {
    name string
    address string
    age int
}

Her opprettes en ny brukerdefinert type kalt emp. Nå kan du lage variabler av typen emp ved å bruke syntaksen

	var variable_name struct_name

Et eksempel er

var empdata1 emp 

Du kan angi verdier for empdata1 as

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

Du kan også lage en strukturvariabel og tilordne verdier etter

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

Her må du opprettholde rekkefølgen på elementene. Raj vil bli tilordnet navn, neste element til adresse og det siste til alder.

Utfør koden nedenfor

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

Produksjon

John
Raj

Metoder (ikke funksjoner)

En metode er en funksjon med et mottakerargument. Archirent teknisk er det mellom func nøkkelordet og metodenavnet. Syntaksen til en metode er

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

La oss konvertere eksempelprogrammet ovenfor til å bruke metoder i stedet for funksjon.

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 er ikke et objektorientert språk, og det har ikke begrepet klasse. Metoder gir en følelse av hva du gjør i objektorienterte programmer der funksjonene til en klasse påkalles ved å bruke syntaksen objektnavn.funksjonsnavn()

samtidighet

Go støtter samtidig utførelse av oppgaver. Det betyr at Go kan utføre flere oppgaver samtidig. Det er forskjellig fra begrepet parallellisme. I parallellisme er en oppgave delt opp i små deloppgaver og utføres parallelt. Men samtidig utføres flere oppgaver samtidig. Samtidig oppnås i Go ved å bruke Goroutines og Channels.

Goroutiner

En goroutine er en funksjon som kan kjøres samtidig med andre funksjoner. Vanligvis når en funksjon påkalles, blir kontrollen overført til den kalte funksjonen, og når den er fullført, går kontrollen tilbake til den anropende funksjonen. Anropsfunksjonen fortsetter deretter utførelsen. Den kallende funksjonen venter på at den påkalte funksjonen fullfører utførelsen før den fortsetter med resten av setningene.

Men i tilfellet med goroutine, vil den anropende funksjonen ikke vente på at utførelsen av den påkalte funksjonen er fullført. Den vil fortsette å kjøre med de neste uttalelsene. Du kan ha flere goroutiner i et program.

Dessuten vil hovedprogrammet avsluttes når det fullfører utføringen av sine uttalelser, og det vil ikke vente på fullføringen av gorutinene som påberopes.

Goroutine påkalles ved hjelp av nøkkelordet go etterfulgt av et funksjonskall.

Eksempel

go add(x,y)

Du vil forstå goroutiner med Golang-eksemplene nedenfor. Utfør programmet nedenfor

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

Utgangen vil være

In main
In main
In main
In main
In main

Her fullførte hovedprogrammet utførelsen allerede før goroutinen startet. Display() er en goroutine som påkalles ved hjelp av syntaksen

go function_name(parameter list)

I koden ovenfor venter ikke main() på at display() skal fullføres, og main() fullførte kjøringen før display() kjørte koden. Så print-setningen i display() ble ikke skrevet ut.

Nå endrer vi programmet for å skrive ut setningene fra display() også. Vi legger til en tidsforsinkelse på 2 sek i for-løkken til main() og 1 sek. forsinkelse i for-løkken til 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")
	}
}

Utgangen vil være noe lik

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

Her kan du se at begge løkkene blir utført på en overlappende måte på grunn av den samtidige utførelsen.

kanaler

Kanaler er en måte for funksjoner å kommunisere med hverandre. Det kan tenkes som et medium til hvor en rutine plasserer data og får tilgang til en annen rutine i Golang-serveren.

En kanal kan deklareres med syntaksen

channel_variable := make(chan datatype)

Eksempel:

	ch := make(chan int)

Du kan sende data til en kanal ved å bruke syntaksen

channel_variable <- variable_name

Eksempel

    ch <- x

Du kan motta data fra en kanal ved å bruke syntaksen

    variable_name := <- channel_variable

Eksempel

   y := <- ch

I de ovennevnte Go-språkeksemplene på goroutine, har du sett at hovedprogrammet ikke venter på goroutinen. Men det er ikke tilfelle når kanaler er involvert. Anta at hvis en goroutine skyver data til kanal, vil main() vente på setningen som mottar kanaldata til den får dataene.

Du vil se dette i eksempler på Go-språk nedenfor. Skriv først en vanlig goroutine og se oppførselen. Endre deretter programmet for å bruke kanaler og se oppførselen.

Utfør programmet nedenfor

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

Utgangen vil være

Inside main()

Main() fullførte utførelsen og avsluttet før goroutinen kjøres. Så utskriften inne i display() ble ikke utført.

Endre nå programmet ovenfor for å bruke kanaler og se oppførselen.

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

Utgangen vil være

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

Her er det som skjer main() ved å nå x := <-ch vil vente på data på kanal ch. Displayet() har en ventetid på 5 sekunder og skyver deretter data til kanalen ch. Main() ved mottak av data fra kanalen blir blokkert og fortsetter kjøringen.

Avsenderen som skyver data til kanal kan informere mottakerne om at det ikke vil bli lagt til flere data til kanalen ved å stenge kanalen. Dette brukes hovedsakelig når du bruker en loop for å skyve data til en kanal. En kanal kan lukkes ved hjelp av

close(channel_name)

Og i mottakerenden er det mulig å sjekke om kanalen er lukket ved hjelp av en ekstra variabel mens man henter data fra kanalen ved hjelp av

variable_name, status := <- channel_variable

Hvis statusen er True, betyr det at du har mottatt data fra kanalen. Hvis falsk, betyr det at du prøver å lese fra en lukket kanal

Du kan også bruke kanaler for kommunikasjon mellom goroutiner. Trenger å bruke 2 goroutiner - en sender data til kanalen og andre mottar data fra kanalen. Se programmet nedenfor

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

Her er det 2 subrutiner, en sender data til kanalen og andre skriver ut data til kanalen. Funksjonen add_to_channel legger til tallene fra 0 til 9 og lukker kanalen. Samtidig venter funksjonen hente_fra_kanal kl

x, flagg := <- ch og når dataene blir tilgjengelige, skriver den ut dataene. Den går ut når flagget er falsk, noe som betyr at kanalen er stengt.

Ventetiden i main() er gitt for å forhindre at main() går ut til goroutinene fullfører utførelsen.

Kjør koden og se utdataene som

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

Velg

Select kan sees på som en brytersetning som fungerer på kanaler. Her vil saksuttalelsene være en kanaloperasjon. Vanligvis vil hver sakserklæring bli lest forsøk fra kanalen. Når noen av sakene er klare (kanalen er lest), blir setningen knyttet til den saken utført. Hvis flere saker er klare, vil den velge en tilfeldig. Du kan ha en standard sak som utføres hvis ingen av sakene er klare.

La oss se koden nedenfor

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

Å kjøre programmet ovenfor vil gi utdata:

from data2()

Her venter select-setningen på at data skal være tilgjengelig i noen av kanalene. Data2() legger til data til kanalen etter en hvilemodus på 2 sekunder, noe som vil føre til at det andre tilfellet kjøres.

Legg til en standard case til select i samme program og se utdataene. Her, når den valgte blokken nås, hvis ingen sak har data klar på kanalen, vil den utføre standardblokken uten å vente på at data skal være tilgjengelig på en 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")
    }
}

Dette programmet vil gi utdata:

Default case executed			

Dette er fordi når valgblokken nådde, hadde ingen kanal data for lesing. Så standardsaken er utført.

mutex

Mutex er kortformen for gjensidig ekskludering. Mutex brukes når du ikke vil tillate tilgang til en ressurs av flere underrutiner samtidig. Mutex har 2 metoder - Lås og Lås opp. Mutex er inneholdt i synkroniseringspakken. Så du må importere synkroniseringspakken. Utsagnene som må eksklusivt utføres gjensidig kan plasseres inne i mutex.Lock() og mutex.Unlock().

La oss lære mutex med et eksempel som teller antall ganger en loop blir utført. I dette programmet forventer vi at rutinen kjører sløyfe 10 ganger og tellingen lagres i sum. Du kaller denne rutinen 3 ganger så det totale antallet skal være 30. Antallet lagres i en global variabeltelling.

Først kjører du programmet uten 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 være annerledes når du utfører det, men det endelige resultatet vil ikke være 30.

Det som skjer her er at 3 goroutiner prøver å øke løkketellingen som er lagret i variabeltellingen. Anta at antallet i et øyeblikk er 5 og goroutine1 kommer til å øke antallet til 6. Hovedtrinnene inkluderer

Kopier telling til temp

Øk temp

Lagre temp tilbake for å telle

Anta kort tid etter å ha utført trinn 3 av goroutine1; en annen goroutine kan ha en gammel verdi, si 3 gjør trinnene ovenfor og lagre 4 tilbake, noe som er feil. Dette kan forhindres ved å bruke mutex som får andre rutiner til å vente når en rutine allerede bruker variabelen.

Nå skal du kjøre programmet med mutex. Her utføres de ovennevnte 3 trinnene 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)
}

Nå blir utgangen

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

Her får vi forventet resultat som sluttresultat. Fordi utsagnene lesing, inkrementering og tilbakeskrivning av telling utføres i en mutex.

Feilhåndtering

Feil er unormale forhold som å lukke en fil som ikke er åpnet, åpne en fil som ikke eksisterer osv. Funksjoner returnerer vanligvis feil som siste returverdi.

Eksempelet nedenfor forklarer mer om feilen.

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

Utgangen vil være:

open /invalid.txt: no such file or directory

Her prøvde vi å åpne en ikke-eksisterende fil, og den returnerte feilen til er variabel. Hvis filen er gyldig, vil feilen være null

Egendefinerte feil

Ved å bruke denne funksjonen kan du lage egendefinerte feil. Dette gjøres ved å bruke New() av ​​feilpakken. Vi vil omskrive programmet ovenfor for å gjøre bruk av egendefinerte feil.

Kjør programmet nedenfor

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

Utgangen vil være:

Custom error message:File name is wrong

Her returnerer arealet () arealet av et kvadrat. Hvis inngangen er mindre enn 1, returnerer area() en feilmelding.

Lese filer

Filer brukes til å lagre data. Go lar oss lese data fra filene

Opprett først en fil, data.txt, i din nåværende katalog med innholdet nedenfor.

Line one
Line two
Line three

Kjør nå programmet nedenfor for å se at det skriver ut innholdet i hele 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))
}

Her leser dataene, err := ioutil.ReadFile(“data.txt”) dataene og returnerer en bytesekvens. Under utskrift konverteres den til strengformat.

Skrive filer

Du vil se dette med et 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
    }
}

Her opprettes en fil, test.txt. Hvis filen allerede eksisterer, avkortes innholdet i filen. Writeline() brukes til å skrive innholdet til filen. Etter det lukket du filen ved å bruke Close().

Cheat Sheet

I denne Go-opplæringen dekket vi,

Emne Tekniske beskrivelser syntax
Grunnleggende typer Numerisk, streng, bool
Variabler Deklarer og tilordne verdier til variabler var variabel_navn type
var variabelnavn type = verdi
var variabelnavn1, variabelnavn2 = verdi1, verdi2
variabelnavn := verdi
Konstant Variabler hvis verdi ikke kan endres når de først er tildelt const variabel = verdi
For Loop Utfør setninger i en løkke. for initialiseringsuttrykk; evalueringsuttrykk; iteration_expression{
// ett eller flere utsagn
}
Hvis ellers Det er en betinget erklæring hvis tilstand{
// utsagn_1
Else {}
// utsagn_2
}
bryter Betinget erklæring med flere saker bytte uttrykk {
case value_1:
utsagn_1
case value_2:
utsagn_2
kasusverdi_n:
utsagn_n
misligholde:
statements_default
}
Array Fast størrelse kalt sekvens av elementer av samme type arrayname := [størrelse] type {value_0,value_1,...,value_size-1}
Slice Del eller segment av en matrise var slice_name [] type = array_name[start:slutt]
Funksjoner Blokk med utsagn som utfører en bestemt oppgave func function_name(parameter_1 type, parameter_n type) return_type {
//utsagn
}
Nettsidepakker Brukes til å organisere koden. Øker kodelesbarhet og gjenbrukbarhet importer pakke_nam
Utsette Utsetter utførelsen av en funksjon til den inneholdende funksjonen er ferdig med kjøringen utsett funksjonsnavn (parameterliste)
pekere Lagrer minneadressen til en annen variabel. var variabelnavn *type
Structure Brukerdefinert datatype som i seg selv inneholder ett element til av samme eller annen type skriv structname struct {
variabel_1 variabel_1_type
variabel_2 variabel_2_type
variabel_n variabel_n_type
}
Metoder En metode er en funksjon med et mottakerargument func (variabel variabeltype) methodName(parameter_list) {
}
Goroutine En funksjon som kan kjøres samtidig med andre funksjoner. gå funksjonsnavn (parameterliste)
Kanal Måte for funksjoner å kommunisere med hverandre. Et medium som en rutine plasserer data til og som er tilgjengelig for en annen rutine. Erklære:
ch := make(chan int)
Send data til kanalen:
kanalvariabel <- variabelnavn
Motta fra kanal:
variabelnavn := <- kanalvariabel
Velg Switch statement som fungerer på kanaler. Saksuttalelsene vil være en kanaldrift. Når en av kanalene er klar med data, blir setningen knyttet til den saken utført velg {
case x := <-chan1:
fmt.Println(x)
case y := <-chan2:
fmt.Println(y)
}
mutex Mutex brukes når du ikke vil tillate tilgang til en ressurs av flere underrutiner samtidig. Mutex har 2 metoder - Lås og Lås opp mutex.Lock()
//utsagn
mutex.Unlock().
Les filer Leser dataene og returnerer en bytesekvens. Data, feil := ioutil.ReadFile(filnavn)
Skriv fil Skriver data til en fil l, feil := f.WriteString(tekst_å_skrive)