Golang-tutorial: Lær Go-programmeringssprog for begyndere
Hvad er Go?
Go (også kendt som Golang) er et open source programmeringssprog udviklet af Google. Det er et statisk skrevet kompileret sprog. Go understøtter samtidig programmering, dvs. det tillader at køre flere processer samtidigt. Dette opnås ved hjælp af kanaler, goroutiner osv. Go Language har skraldopsamling, som selv udfører hukommelseshåndteringen og tillader udskudt udførelse af funktioner.
Vi vil lære alt det grundlæggende om Golang i denne Lær Go Language Tutorial.
Sådan downloades og installeres GO
Trin 1) Gå til https://golang.org/dl/. Download binær til dit OS.
Trin 2) Double klik på installationsprogrammet og klik på Kør.
Trin 3) Klik på Næste
Trin 4) Vælg installationsmappen, og klik på Næste.
Trin 5) Klik på Udfør, når installationen er fuldført.
Trin 6) Når installationen er færdig, kan du bekræfte den ved at åbne terminalen og skrive
go version
Dette vil vise versionen af go installeret
Dit First Go-program – Go Hello World!
Opret en mappe kaldet studyGo. I denne Go-sprogtutorial vil vi oprette vores go-programmer i denne mappe. Go-filer oprettes med udvidelsen .gå. Du kan køre Go-programmer ved hjælp af syntaksen
go run <filename>
Opret en fil kaldet first.go og tilføj nedenstående kode i den og gem
package main import ("fmt") func main() { fmt.Println("Hello World! This is my first Go program\n") }
Naviger til denne mappe i din terminal. Kør programmet ved hjælp af kommandoen
gå løb først.gå
Du kan se output-udskrivningen
Hello World! This is my first Go program
Lad os nu diskutere ovenstående program.
hovedpakke – Hvert Go Language-program skal starte med et pakkenavn. Go giver os mulighed for at bruge pakker i andre go-programmer og understøtter derfor genbrugbar kode. Udførelse af et Go-program begynder med koden inde i pakken med navnet main.
import fmt – importerer pakken fmt. Denne pakke implementerer I/O-funktionerne.
func main() – Dette er den funktion, hvorfra programafviklingen begynder. Hovedfunktionen skal altid placeres i hovedpakken. Under main() kan du skrive koden inde i { }.
fmt.Println – Dette vil udskrive teksten på skærmen ved hjælp af Println-funktionen i fmt.
Bemærk: I nedenstående sektioner af denne Go-tutorial, når du nævner eksekver/kør koden, betyder det at gemme koden i en fil med .go-udvidelsen og køre den ved hjælp af syntaksen
go run <filename>
Datatyper
Typer (datatyper) repræsenterer typen af værdien gemt i en variabel, typen af værdien en funktion returnerer osv.
Der er tre grundlæggende typer i Go Language
Numeriske typer – Repræsenterer numeriske værdier, som inkluderer heltal, flydende komma og komplekse værdier. Forskellige numeriske typer er:
int8 – 8 bit signerede heltal.
int16 – 16 bit signerede heltal.
int32 – 32 bit signerede heltal.
int64 – 64 bit signerede heltal.
uint8 – 8 bit usignerede heltal.
uint16 – 16 bit usignerede heltal.
uint32 – 32 bit usignerede heltal.
uint64 – 64 bit usignerede heltal.
flydende 32 – 32 bit flydende kommatal.
flydende 64 – 64 bit flydende kommatal.
complex64 – har float32 reelle og imaginære dele.
complex128 – har float32 reelle og imaginære dele.
Strengetyper – Repræsenterer en sekvens af bytes(tegn). Du kan udføre forskellige operationer på strenge som strengsammenkædning, udtrækning af understreng osv
booleske typer – Repræsenterer 2 værdier, enten sande eller falske.
Golang grænseflade
Golang grænseflade er en samling af metodesignaturer, der bruges af en Type til at implementere objekters adfærd. Hovedmålet med Golang-grænsefladen er at give metodesignaturer med navne, argumenter og returtyper. Det er op til en Type at erklære og implementere metoden. En grænseflade i Golang kan erklæres ved hjælp af søgeordet "grænseflade".
Variabler
Variabler peger på en hukommelsesplacering, som gemmer en form for værdi. Typeparameteren (i nedenstående syntaks) repræsenterer den type værdi, der kan gemmes i hukommelsesplaceringen.
Variabel kan erklæres ved hjælp af syntaksen
var <variable_name> <type>
Når du erklærer en variabel af en type, kan du tildele variablen til enhver værdi af den type.
Du kan også give en startværdi til en variabel under selve deklarationen ved hjælp af
var <variable_name> <type> = <value>
Hvis du erklærer variablen med en begyndelsesværdi, skal du gå og udlede variablens type ud fra den tildelte værditype. Så du kan udelade typen under erklæringen ved hjælp af syntaksen
var <variable_name> = <value>
Du kan også erklære flere variabler med syntaksen
var <variable_name1>, <variable_name2> = <value1>, <value2>
Nedenstående program i denne Go-tutorial har nogle Golang-eksempler på variable erklæringer
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) }
Udgangen bliver
x: 3 y: 20 z: 50 i and j: 100 hello
Go Language giver også en nem måde at erklære variablerne med værdi ved at udelade nøgleordet var ved at bruge
<variable_name> := <value>
Bemærk, at du brugte := i stedet for =. Du kan ikke bruge := bare til at tildele en værdi til en variabel, som allerede er deklareret. := bruges til at erklære og tildele værdi.
Opret en fil kaldet 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) }
Udfør go run assign.go for at se resultatet som
./assign.go:7:4: no new variables on left side of :=
Variabler erklæret uden en startværdi vil have 0 for numeriske typer, falsk for boolesk og tom streng for strenge
Konstanter
Konstante variabler er de variable, hvis værdi ikke kan ændres, når de først er tildelt. En konstant i Go programmeringssprog erklæres ved at bruge søgeordet "const"
Opret en fil kaldet constant.go og med følgende kode
package main import ("fmt") func main() { const b =10 fmt.Println(b) b = 30 fmt.Println(b) }
Udfør go run constant.go for at se resultatet som
.constant.go:7:4: cannot assign to b
For løkkeeksempler
Sløjfer bruges til at udføre en blok af udsagn gentagne gange baseret på en betingelse. De fleste programmeringssprog giver 3 typer loops - for, mens, do while. Men Go-programmeringssproget understøtter kun loop.
Syntaksen for en Golang for loop er
for initialisation_expression; evaluation_expression; iteration_expression{ // one or more statement }
Initialiseringsudtrykket udføres først (og kun én gang) i Golang for loop.
Derefter evalueres evaluation_expression, og hvis det er sandt, udføres koden inde i blokken.
Iteration_expression-id'et udføres, og evaluation_expression evalueres igen. Hvis det er sandt, udføres sætningsblokken igen. Dette vil fortsætte, indtil evaluation_expression bliver falsk.
Kopier nedenstående program ind i en fil og kør den for at se Golang for loop-udskrivningsnumre 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 andet er en betinget erklæring. Synaksen er
if condition{ // statements_1 }else{ // statements_2 }
Her evalueres betingelsen, og hvis den er sand, vil statements_1 blive eksekveret, ellers vil statements_2 blive eksekveret.
Du kan også bruge if-sætning uden andet. Du kan også have lænket if else-udsagn. Nedenstående programmer vil forklare mere om, hvis andet.
Udfør nedenstående program. Den kontrollerer, om et tal, x, er mindre end 10. Hvis det er tilfældet, vil den udskrive "x er mindre end 10"
package main import "fmt" func main() { var x = 50 if x < 10 { //Executes if x < 10 fmt.Println("x is less than 10") } }
Da værdien af x her er større end 10, vil sætningen inde i if-blokbetingelsen ikke blive udført.
Se nu nedenstående program. I denne Go-programmeringssprogstutorial har vi en anden blok, som vil blive udført ved fejl 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 program vil give dig output
x is greater than or equals 10
Nu i denne Go-tutorial vil vi se et program med flere if else-blokke (kædet hvis andet). Udfør nedenstående Go-eksempel. Den kontrollerer, om et tal er mindre end 10 eller er mellem 10-90 eller større end 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-betingelsen, om x er mindre end 10, og det er den ikke. Så det tjekker den næste betingelse (ellers hvis), om den er mellem 10 og 90, hvilket også er falsk. Så den udfører derefter blokken under else-sektionen, som giver output
x is greater than 90
Kontakt
Switch er en anden betinget erklæring. Switch-sætninger evaluerer et udtryk, og resultatet sammenlignes med et sæt tilgængelige værdier(cases). Når et match er fundet, udføres de udsagn, der er knyttet til det match(casus). Hvis der ikke findes noget match, vil intet blive udført. Du kan også tilføje en standard case til at skifte, som vil blive udført, hvis der ikke findes andre matches. Syntaksen for switchen er
switch expression { case value_1: statements_1 case value_2: statements_2 case value_n: statements_n default: statements_default }
Her sammenlignes udtrykkets værdi med værdierne i hvert enkelt tilfælde. Når et match er fundet, udføres de erklæringer, der er knyttet til den pågældende sag. Hvis der ikke findes noget match, udføres sætningerne under standardafsnittet.
Udfør nedenstående program
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 får output som
Sum is 3
Ændre værdien af a og b til 3 og resultatet bliver
Printing default
Du kan også have flere værdier i en sag ved at adskille dem med et komma.
Arrays
Array repræsenterer en fast størrelse, navngivet sekvens af elementer af samme type. Du kan ikke have en matrix, der indeholder både heltal og tegn. Du kan ikke ændre størrelsen på et array, når først du har defineret størrelsen.
Syntaksen til at erklære et array er
var arrayname [size] type
Hvert array-element kan tildeles værdi ved hjælp af syntaksen
arrayname [index] = value
Array-indeks starter fra 0 til størrelse-1.
Du kan tildele værdier til matrixelementer under erklæringen ved hjælp af syntaksen
arrayname := [size] type {value_0,value_1,…,value_size-1}
Du kan også ignorere størrelsesparameteren, mens du erklærer arrayet med værdier ved at erstatte størrelse med ... og compileren vil finde længden ud fra antallet af værdier. Syntaks er
arrayname := […] type {value_0,value_1,…,value_size-1}
Du kan finde længden af arrayet ved at bruge syntaksen
len(arrayname)
Udfør nedenstående Go-eksempel for at forstå arrayet
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 skive er en del eller et segment af et array. Eller det er en visning eller delvis visning af en underliggende matrix, som den peger på. Du kan få adgang til elementerne i et udsnit ved hjælp af udsnitsnavnet og indeksnummeret, ligesom du gør i et array. Du kan ikke ændre længden af et array, men du kan ændre størrelsen på et udsnit.
Indholdet af en skive er faktisk pejlemærkerne til elementerne i et array. Det betyder hvis du ændrer et element i et udsnit, vil det underliggende matrixindhold også blive påvirket.
Syntaksen for at oprette et udsnit er
var slice_name [] type = array_name[start:end]
Dette vil oprette et udsnit ved navn udsnit_navn fra et array ved navn array_navn med elementerne ved indekset start til slut-1.
Nu i denne Golang tutorial, vil vi udføre nedenstående program. Programmet vil oprette et udsnit fra arrayet og udskrive det. Du kan også se, at ændring af indholdet i udsnittet vil ændre det faktiske array.
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 udskrive 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]
Der er visse funktioner som Golang len, Golang append, som du kan anvende på skiver
len(slice_name) – returnerer længden af skiven
tilføje(udsnit_navn, værdi_1, værdi_2) – Golang append bruges til at tilføje værdi_1 og værdi_2 til et eksisterende udsnit.
tilføje(udsnit_nale1,udsnit_navn2...) – føjer udsnit_navn2 til udsnit_navn1
Udfø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) }
Udgangen bliver
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 opretter først 2 skiver og udskrev dens længde. Derefter føjede den en skive til den anden og føjede derefter en streng til den resulterende skive.
Funktioner
En funktion repræsenterer en blok af udsagn, som udfører en bestemt opgave. En funktionserklæring fortæller os funktionsnavn, returtype og inputparametre. Funktionsdefinition repræsenterer koden indeholdt i funktionen. Syntaksen til at erklære funktionen er
func function_name(parameter_1 type, parameter_n type) return_type { //statements }
Parametrene og returtyperne er valgfrie. Du kan også returnere flere værdier fra en funktion.
Lad os nu i denne Golang-tutorial køre følgende Golang-eksempel. Her vil en funktion kaldet calc acceptere 2 tal og udføre addition og subtraktion og returnerer begge værdier.
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) }
Udgangen bliver
Sum 25 Diff 5
Pakker
Pakker bruges til at organisere koden. I et stort projekt er det ikke muligt at skrive kode i en enkelt fil. Go programmeringssprog giver os mulighed for at organisere koden under forskellige pakker. Dette øger kodelæsbarheden og genbrugbarheden. Et eksekverbart Go-program bør indeholde en pakke med navnet main, og programafviklingen starter fra funktionen med navnet main. Du kan importere andre pakker i vores program ved hjælp af syntaksen
import package_name
Vi vil se og diskutere i denne Golang-tutorial, hvordan man opretter og bruger pakker i det følgende Golang-eksempel.
Trin 1) Opret en fil kaldet package_example.go og tilføj nedenstående kode
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 ovenstående program er fmt en pakke, som Go-programmeringssproget giver os hovedsageligt til I/O-formål. Du kan også se en pakke med navnet beregning. Inde i main() kan du se en trinsum := beregning.Do_add(x,y). Det betyder, at du aktiverer funktionen Do_add fra pakkeberegning.
Trin 2) Først skal du oprette pakkeberegningen inde i en mappe med samme navn under src-mappen på farten. Den installerede sti til go kan findes fra PATH-variablen.
For mac, find stien ved at udføre echo $PATH
Så stien er /usr/local/go
For Windows, find stien ved at udføre echo %GOROOT%
Her er stien C:\Go\
Trin 3) Naviger til mappen src (/usr/local/go/src til mac og C:\Go\src til Windows). Nu fra koden er pakkenavnet beregning. Go kræver, at pakken skal placeres i en mappe af samme navn under src-mappen. Opret en mappe med navnet beregning i mappen src.
Trin 4) Opret en fil kaldet calc.go (Du kan give et hvilket som helst navn, men pakkenavnet i koden betyder noget. Her skal det være beregning) inde i beregningsmappen og tilføj nedenstående kode
package calculation func Do_add(num1 int, num2 int)(int) { sum := num1 + num2 return sum }
Trin 5) Kør kommandoen go install fra beregningsmappen, som vil kompilere calc.go.
Trin 6) Gå nu tilbage til package_example.go og kør go run package_example.go. Outputtet vil være Sum 25.
Bemærk, at navnet på funktionen Do_add starter med et stort bogstav. Dette skyldes, at i Go, hvis funktionsnavnet starter med et stort bogstav, betyder det, at andre programmer kan se (få adgang), ellers kan andre programmer ikke få adgang til det. Hvis funktionsnavnet var do_add , så ville du have fået fejlen
kan ikke henvise til ueksporteret navneberegning.beregning..
Defer og stabling udskyder
Defer-sætninger bruges til at udskyde udførelsen af et funktionskald, indtil funktionen, der indeholder defer-sætningen, fuldfører udførelsen.
Lad os 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()") }
Udgangen bliver
Inside the main() Inside the sample()
Her udsættes udførelsen af sample() indtil udførelsen af den omsluttende funktion(main()) er fuldført.
Stacking defer bruger flere defer-udsagn. Antag, at du har flere defer-sætninger inde i en funktion. Go placerer alle de udskudte funktionskald i en stak, og når den omsluttende funktion vender tilbage, udføres de stablede funktioner i Last In First Out (LIFO) rækkefølge. Du kan se dette i eksemplet nedenfor.
Udfør nedenstående kode
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) }
Udgangen bliver
4 3 2 1
Her udføres koden inde i main() først, og derefter udføres de udskudte funktionskald i omvendt rækkefølge, dvs. 4, 3,2,1.
Pointers
Før vi forklarer pointer, lad os først diskutere '&'-operatoren. Operatoren '&' bruges til at få adressen på en variabel. Det betyder, at '&a' vil udskrive hukommelsesadressen for variabel a.
I denne Golang tutorial vil vi udføre nedenstående program for at vise værdien af en variabel og adressen på den variabel
package main import "fmt" func main() { a := 20 fmt.Println("Address:",&a) fmt.Println("Value:",a) }
Resultatet bliver
Address: 0xc000078008 Value: 20
En pointervariabel gemmer hukommelsesadressen for en anden variabel. Du kan definere en markør ved hjælp af syntaksen
var variable_name *type
Stjernen(*) repræsenterer variablen er en pointer. Du vil forstå mere ved at udføre nedenstående program
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)}
Udgangen bliver
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 er en brugerdefineret datatype, som i sig selv indeholder et element mere af samme eller anden type.
Brug af en struktur er en 2-trins proces.
Først skal du oprette (erklære) en strukturtype
For det andet skal du oprette variabler af den type for at gemme værdier.
Strukturer bruges hovedsageligt, når du vil gemme relaterede data sammen.
Overvej et stykke medarbejderinformation, som har navn, alder og adresse. Du kan håndtere dette på 2 måder
Opret 3 arrays – et array gemmer medarbejdernes navne, et lagrer alder og det tredje lagrer alder.
Angiv en strukturtype med 3 felter - navn, adresse og alder. Opret en matrix af den strukturtype, hvor hvert element er et strukturobjekt med navn, adresse og alder.
Den første tilgang er ikke effektiv. I den slags scenarier er strukturer mere bekvemme.
Syntaksen til at erklære 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 strukturdeklaration er
type emp struct { name string address string age int }
Her oprettes en ny brugerdefineret type ved navn emp. Nu kan du oprette variabler af typen emp ved hjælp af syntaksen
var variable_name struct_name
Et eksempel er
var empdata1 emp
Du kan indstille værdier for empdata1 as
empdata1.name = "John" empdata1.address = "Street-1, Bangalore" empdata1.age = 30
Du kan også oprette en strukturvariabel og tildele værdier ved
empdata2 := emp{"Raj", "Building-1, Delhi", 25}
Her skal du bevare rækkefølgen af elementer. Raj vil blive kortlagt til navn, næste element til adresse og det sidste til alder.
Udfø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) }
Produktion
John Raj
Metoder (ikke funktioner)
En metode er en funktion med et modtagerargument. Archirent teknisk er det mellem func nøgleordet og metodenavnet. Syntaksen for en metode er
func (variable variabletype) methodName(parameter1 paramether1type) { }
Lad os konvertere ovenstående eksempelprogram til at bruge metoder i stedet for 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 er ikke et objektorienteret sprog, og det har ikke begrebet klasse. Metoder giver en fornemmelse af, hvad du gør i objektorienterede programmer, hvor funktionerne i en klasse påkaldes ved hjælp af syntaksen objektnavn.funktionsnavn()
samtidighed
Go understøtter samtidig udførelse af opgaver. Det betyder, at Go kan udføre flere opgaver samtidigt. Det er forskelligt fra begrebet parallelisme. I parallelisme er en opgave opdelt i små delopgaver og udføres parallelt. Men samtidig udføres flere opgaver samtidigt. Samtidig opnås i Go ved hjælp af Goroutines og Channels.
Goroutiner
En goroutine er en funktion, der kan køre samtidig med andre funktioner. Normalt, når en funktion påkaldes, overføres kontrollen til den kaldte funktion, og når dens afsluttede udførelseskontrol vender tilbage til den kaldende funktion. Den kaldende funktion fortsætter derefter sin udførelse. Den kaldende funktion venter på, at den påkaldte funktion fuldfører udførelsen, før den fortsætter med resten af sætningerne.
Men i tilfælde af goroutine, vil den kaldende funktion ikke vente på, at udførelsen af den påkaldte funktion er fuldført. Det vil fortsætte med at udføre med de næste erklæringer. Du kan have flere goroutiner i et program.
Hovedprogrammet afsluttes også, når det er færdigt med at udføre sine udsagn, og det vil ikke vente på færdiggørelsen af de påberåbte goroutiner.
Goroutine påkaldes ved hjælp af nøgleordet go efterfulgt af et funktionskald.
Eksempel
go add(x,y)
Du vil forstå goroutiner med nedenstående Golang-eksempler. Udfør nedenstående program
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") } }
Udgangen bliver
In main In main In main In main In main
Her afsluttede hovedprogrammet eksekveringen, allerede før goroutinen startede. Display() er en goroutine, som fremkaldes ved hjælp af syntaksen
go function_name(parameter list)
I ovenstående kode venter main() ikke på, at display() er færdig, og main() fuldførte sin udførelse, før display() udførte sin kode. Så print-erklæringen inde i display() blev ikke udskrevet.
Nu ændrer vi programmet til også at udskrive udsagn fra display(). Vi tilføjer en tidsforsinkelse på 2 sek. i for-løkken i main() og en forsinkelse på 1 sek. i for-løkken 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") } }
Outputtet vil ligne noget
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 loops udføres på en overlappende måde på grund af den samtidige udførelse.
Kanaler
Kanaler er en måde, hvorpå funktioner kan kommunikere med hinanden. Det kan opfattes som et medium til, hvor en rutine placerer data og tilgås af en anden rutine i Golang-serveren.
En kanal kan erklæres med syntaksen
channel_variable := make(chan datatype)
Eksempel:
ch := make(chan int)
Du kan sende data til en kanal ved hjælp af syntaksen
channel_variable <- variable_name
Eksempel
ch <- x
Du kan modtage data fra en kanal ved hjælp af syntaksen
variable_name := <- channel_variable
Eksempel
y := <- ch
I ovenstående Go-sprogeksempler på goroutine har du set, at hovedprogrammet ikke venter på goroutinen. Men det er ikke tilfældet, når kanaler er involveret. Antag, at hvis en goroutine skubber data til kanal, vil main() vente på sætningen, der modtager kanaldata, indtil den får dataene.
Du vil se dette i nedenstående Go sprogeksempler. Skriv først en normal goroutine og se adfærden. Rediger derefter programmet til at bruge kanaler og se adfærden.
Udfør nedenstående program
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()") }
Udgangen bliver
Inside main()
Main() afsluttede udførelsen og afsluttede før goroutinen eksekveres. Så udskriften inde i display() blev ikke udført.
Rediger nu ovenstående program for at bruge kanaler og se adfærden.
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) }
Udgangen bliver
Inside display() Inside main() Printing x in main() after taking from channel: 1234
Her, hvad der sker, er main() ved at nå x := <-ch vil vente på data på kanal ch. Displayet() har en ventetid på 5 sekunder og skubber derefter data til kanalen ch. Main() ved modtagelse af data fra kanalen bliver blokeret og fortsætter sin eksekvering.
Afsenderen, der pusher data til kanal, kan informere modtagerne om, at der ikke vil blive tilføjet flere data til kanalen ved at lukke kanalen. Dette bruges hovedsageligt, når du bruger en loop til at skubbe data til en kanal. En kanal kan lukkes vha
close(channel_name)
Og i modtagerenden er det muligt at kontrollere, om kanalen er lukket ved hjælp af en ekstra variabel, mens der hentes data fra kanalen vha.
variable_name, status := <- channel_variable
Hvis status er Sand, betyder det, at du har modtaget data fra kanalen. Hvis falsk, betyder det, at du forsøger at læse fra en lukket kanal
Du kan også bruge kanaler til kommunikation mellem goroutiner. Skal bruge 2 goroutiner - den ene skubber data til kanalen og den anden modtager dataene fra kanalen. Se nedenstående program
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 der 2 underrutiner, den ene skubber data til kanalen og den anden udskriver data til kanalen. Funktionen add_to_channel tilføjer tallene fra 0 til 9 og lukker kanalen. Samtidig venter funktionen fetch_from_channel kl
x, flag := <- ch og når dataene bliver tilgængelige, udskriver den dataene. Den afsluttes, når flaget er falsk, hvilket betyder, at kanalen er lukket.
Ventetiden i main() er givet for at forhindre, at main() forlades, indtil goroutinerne afslutter udførelsen.
Udfør koden og se output som
Read data Send data 0 1 2 3 4 5 6 7 8 9 Empty channel Inside main()
Type
Select kan ses som en switch-erklæring, der fungerer på kanaler. Her vil sagsfremstillingerne være en kanaloperation. Normalt vil hver case-udsagn blive læst forsøg fra kanalen. Når nogen af sagerne er klar (kanalen læses), udføres den erklæring, der er knyttet til sagen. Hvis flere sager er klar, vil den vælge en tilfældig. Du kan have en standardsag, som udføres, hvis ingen af sagerne er klar.
Lad os se nedenstående kode
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) } }
Udførelse af ovenstående program vil give output:
from data2()
Her venter select-erklæringen på, at data er tilgængelige i nogen af kanalerne. Data2() tilføjer data til kanalen efter en dvale på 2 sekunder, hvilket vil få det andet tilfælde til at udføres.
Tilføj en standard case til valget i det samme program og se outputtet. Her, når den valgte blok er nået, hvis ingen sag har data klar på kanalen, vil den udføre standardblokken uden at vente på, at data er tilgængelige på nogen 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 program vil give output:
Default case executed
Dette skyldes, at når den valgte blok nåede, havde ingen kanal data til læsning. Så standardsagen udføres.
mutex
Mutex er den korte form for gensidig udelukkelse. Mutex bruges, når du ikke ønsker at tillade, at en ressource skal tilgås af flere underrutiner på samme tid. Mutex har 2 metoder - Lås og Lås op. Mutex er indeholdt i sync-pakken. Så du skal importere synkroniseringspakken. Udsagn, der skal udføres gensidigt, kan placeres i mutex.Lock() og mutex.Unlock().
Lad os lære mutex med et eksempel, der tæller antallet af gange, en loop udføres. I dette program forventer vi, at rutinen kører loop 10 gange, og tællingen er gemt i sum. Du kalder denne rutine 3 gange, så det samlede antal skal være 30. Optællingen er gemt i en global variabel optælling.
Først kører du programmet uden 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 anderledes, når du udfører det, men det endelige resultat vil ikke være 30.
Her, hvad der sker, er 3 goroutiner, der forsøger at øge sløjfeantallet, der er gemt i det variable antal. Antag, at tallet på et tidspunkt er 5, og goroutine1 vil øge tallet til 6. De vigtigste trin omfatter
Kopier tæller til temp
Øg temp
Gem temperaturen tilbage for at tælle
Antag kort efter at have udført trin 3 ved goroutine1; en anden goroutine kan have en gammel værdi, f.eks. 3 udfører ovenstående trin og gemmer 4 tilbage, hvilket er forkert. Dette kan forhindres ved at bruge mutex, som får andre rutiner til at vente, når en rutine allerede bruger variablen.
Nu vil du køre programmet med mutex. Her udføres de ovennævnte 3 trin 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 bliver outputtet
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 det forventede resultat som endeligt output. Fordi udsagn læsning, stigning og tilbageskrivning af optælling udføres i en mutex.
Fejl ved håndtering
Fejl er unormale forhold som at lukke en fil, der ikke er åbnet, åbne en fil, der ikke eksisterer, osv. Funktioner returnerer normalt fejl som den sidste returværdi.
Nedenstående eksempel forklarer mere om fejlen.
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") }
Outputtet vil være:
open /invalid.txt: no such file or directory
Her forsøgte vi at åbne en ikke-eksisterende fil, og den returnerede fejlen til er variabel. Hvis filen er gyldig, vil fejlen være nul
Brugerdefinerede fejl
Ved at bruge denne funktion kan du oprette brugerdefinerede fejl. Dette gøres ved at bruge New() i fejlpakken. Vi vil omskrive ovenstående program for at gøre brug af brugerdefinerede fejl.
Kør nedenstående program
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) } }
Outputtet vil være:
Custom error message:File name is wrong
Her returnerer arealet () arealet af et kvadrat. Hvis input er mindre end 1, returnerer area() en fejlmeddelelse.
Læsning af filer
Filer bruges til at gemme data. Go giver os mulighed for at læse data fra filerne
Opret først en fil, data.txt, i din nuværende mappe med nedenstående indhold.
Line one Line two Line three
Kør nu nedenstående program for at se, at det udskriver indholdet af hele filen som output
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 læser dataene, err := ioutil.ReadFile(“data.txt”) dataene og returnerer en bytesekvens. Under udskrivning konverteres den til strengformat.
Skrivning af 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 oprettes en fil, test.txt. Hvis filen allerede eksisterer, afkortes indholdet af filen. Writeline() bruges til at skrive indholdet til filen. Derefter lukkede du filen ved hjælp af Close().
Cheat Sheet
I denne Go-tutorial dækkede vi,
Emne | Description | Syntaks |
---|---|---|
Grundlæggende typer | Numerisk, streng, bool | |
Variabler | Erklære og tildele værdier til variabler | var variabel_navn type var variabelnavn type = værdi var variabel_navn1, variabel_navn2 = værdi1, værdi2 variabelnavn := værdi |
Konstanter | Variabler, hvis værdi ikke kan ændres, når de først er tildelt | const variabel = værdi |
Til Loop | Udfør sætninger i en løkke. | for initialiseringsudtryk; evaluation_expression; iteration_expression{ // en eller flere udsagn } |
Hvis ellers | Det er en betinget erklæring | hvis betingelse{ // udsagn_1 Else {} // udsagn_2 } |
skifte | Betinget erklæring med flere sager | skifte udtryk { case value_1: udsagn_1 case value_2: udsagn_2 case value_n: udsagn_n Standard: statements_default } |
Array | Fast størrelse navngivet sekvens af elementer af samme type | matrixnavn := [størrelse] type {værdi_0, værdi_1,..., værdi_størrelse-1} |
Slice | Del eller segment af et array | var slice_name [] type = array_name[start:slut] |
Funktioner | Blok af udsagn, der udfører en bestemt opgave | func funktionsnavn(parameter_1 type, parameter_n type) return_type { //udsagn } |
Pakker | Bruges til at organisere koden. Øger kodelæsbarhed og genbrugbarhed | importer pakke_nam |
Udsætte | Udsætter udførelsen af en funktion, indtil den indeholdende funktion afslutter udførelsen | udskyde funktionsnavn (parameterliste) |
Pointers | Gemmer hukommelsesadressen for en anden variabel. | var variabelnavn *type |
Struktur | Brugerdefineret datatype, som i sig selv indeholder et element mere af samme eller anden type | skriv structname struct { variabel_1 variabel_1_type variabel_2 variabel_2_type variabel_n variabel_n_type } |
Metoder | En metode er en funktion med et modtagerargument | func (variabel variabeltype) methodName(parameter_list) { } |
Goroutine | En funktion, der kan køre samtidig med andre funktioner. | gå funktionsnavn (parameterliste) |
Kanal | Måde for funktioner at kommunikere med hinanden. Et medie, hvor en rutine placerer data og tilgås af en anden rutine. | Erklære: ch := make(chan int) Send data til kanal: kanalvariabel <- variabel_navn Modtag fra kanal: variabel_navn := <- kanalvariabel |
Type | Switch statement, der virker på kanaler. Sagsudtalelserne vil være en kanaloperation. Når en af kanalerne er klar med data, udføres den erklæring, der er knyttet til den pågældende sag | Vælg { case x := <-chan1: fmt.Println(x) case y := <-chan2: fmt.Println(y) } |
mutex | Mutex bruges, når du ikke ønsker at tillade, at en ressource skal tilgås af flere underrutiner på samme tid. Mutex har 2 metoder - Lås og Lås op | mutex.Lock() //udsagn mutex.Unlock(). |
Læs filer | Læser dataene og returnerer en bytesekvens. | Data, fejl := ioutil.ReadFile(filnavn) |
Skriv fil | Skriver data til en fil | l, fejl := f.WriteString(text_to_write) |