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