Vodič za Golang
Što je Go?
Go (također poznat kao Golang) je programski jezik otvorenog koda koji je razvio Google. To je statički tipiziran kompilirani jezik. Go podržava istovremeno programiranje, tj. omogućuje pokretanje više procesa istovremeno. To se postiže korištenjem kanala, goroutina itd. Go Language ima skupljanje smeća koje samo upravlja memorijom i omogućuje odgođeno izvršavanje funkcija.
Naučit ćemo sve osnove Golanga u ovom vodiču za učenje jezika.
Kako preuzeti i instalirati GO
Korak 1) Idi na https://golang.org/dl/. Preuzmite binarnu verziju za svoj OS.
Korak 2) Double kliknite na instalacijski program i kliknite Pokreni.
Korak 3) Kliknite Dalje
Korak 4) Odaberite instalacijsku mapu i kliknite Dalje.
Korak 5) Kliknite Završi kada instalacija završi.
Korak 6) Nakon dovršetka instalacije možete je provjeriti otvaranjem terminala i upisivanjem
go version
Ovo će prikazati instaliranu verziju programa go
Vaš prvi Go program – Go Hello World!
Napravite mapu pod nazivom studyGo. U ovom vodiču za jezik Go stvorit ćemo naše go programe unutar ove mape. Go datoteke izrađuju se s ekstenzijom .ići. Go programe možete pokretati pomoću sintakse
go run <filename>
Napravite datoteku pod nazivom first.go i dodajte donji kod u nju i spremite
package main import ("fmt") func main() { fmt.Println("Hello World! This is my first Go program\n") }
Dođite do ove mape na svom terminalu. Pokrenite program pomoću naredbe
idi trči prvi.idi
Možete vidjeti izlazni ispis
Hello World! This is my first Go program
Raspravljajmo sada o gore navedenom programu.
glavni paket – Svaki Go Language program trebao bi započeti nazivom paketa. Go nam omogućuje korištenje paketa u drugim go programima i stoga podržava ponovnu upotrebu koda. Izvršenje Go programa počinje kodom unutar paketa pod nazivom main.
import fmt – uvozi paket fmt. Ovaj paket implementira I/O funkcije.
func main() – Ovo je funkcija od koje počinje izvršavanje programa. Glavnu funkciju uvijek treba staviti u glavni paket. Pod main(), možete napisati kod unutar { }.
fmt.Println – Ovo će ispisati tekst na ekranu pomoću funkcije Println funkcije fmt.
Napomena: U donjim odjeljcima ovog vodiča za Go, kada spomenete izvrši/pokreni kod, to znači da treba spremiti kod u datoteku s nastavkom .go i pokrenuti ga pomoću sintakse
go run <filename>
Vrste podataka
Tipovi (tipovi podataka) predstavljaju tip vrijednosti pohranjene u varijabli, tip vrijednosti koju funkcija vraća itd.
Postoje tri osnovne vrste u Go jeziku
Numerički tipovi – Predstavljaju numeričke vrijednosti koje uključuju cijeli broj, pokretni zarez i složene vrijednosti. Različiti numerički tipovi su:
int8 – 8-bitni cijeli brojevi s predznakom.
int16 – 16-bitni cijeli brojevi s predznakom.
int32 – 32-bitni cijeli brojevi s predznakom.
int64 – 64-bitni cijeli brojevi s predznakom.
uint8 – 8-bitni cijeli brojevi bez predznaka.
uint16 – 16-bitni cijeli brojevi bez predznaka.
uint32 – 32-bitni cijeli brojevi bez predznaka.
uint64 – 64-bitni cijeli brojevi bez predznaka.
float32 – 32-bitni brojevi s pomičnim zarezom.
float64 – 64-bitni brojevi s pomičnim zarezom.
complex64 – ima float32 realne i imaginarne dijelove.
complex128 – ima float32 realne i imaginarne dijelove.
Vrste nizova – Predstavlja niz bajtova (karaktera). Možete raditi razne operacije na nizovima kao što su spajanje nizova, izdvajanje podniza itd
Booleovi tipovi – Predstavlja 2 vrijednosti, istinito ili lažno.
Golang sučelje
Golang sučelje je zbirka potpisa metoda koje tip koristi za implementaciju ponašanja objekata. Glavni cilj sučelja Golang je osigurati potpise metoda s imenima, argumentima i vrstama povrata. Na Tipu je da deklarira i implementira metodu. Sučelje u Golangu može se deklarirati pomoću ključne riječi "interface."
Varijable
Varijable pokazuju na memorijsku lokaciju koja pohranjuje neku vrstu vrijednosti. Parametar vrste (u donjoj sintaksi) predstavlja vrstu vrijednosti koja se može pohraniti na memorijsku lokaciju.
Varijabla se može deklarirati pomoću sintakse
var <variable_name> <type>
Jednom kada deklarirate varijablu nekog tipa, možete dodijeliti varijablu bilo kojoj vrijednosti tog tipa.
Također možete dati početnu vrijednost varijabli tijekom same deklaracije koristeći
var <variable_name> <type> = <value>
Ako deklarirate varijablu s početnom vrijednošću, Go i zaključite vrstu varijable iz vrste dodijeljene vrijednosti. Dakle, možete izostaviti tip tijekom deklaracije pomoću sintakse
var <variable_name> = <value>
Također, možete deklarirati više varijabli sa sintaksom
var <variable_name1>, <variable_name2> = <value1>, <value2>
Donji program u ovom vodiču za Go ima neke Golang primjere deklaracija varijabli
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) }
Izlaz će biti
x: 3 y: 20 z: 50 i and j: 100 hello
Go Language također pruža jednostavan način deklariranja varijabli s vrijednošću izostavljanjem ključne riječi var using
<variable_name> := <value>
Imajte na umu da ste koristili := umjesto =. Ne možete koristiti := samo za dodjelu vrijednosti varijabli koja je već deklarirana. := se koristi za deklariranje i dodjeljivanje vrijednosti.
Stvorite datoteku pod nazivom assign.go sa sljedećim kodom
package main import ("fmt") func main() { a := 20 fmt.Println(a) //gives error since a is already declared a := 30 fmt.Println(a) }
Izvršite go run assign.go da vidite rezultat kao
./assign.go:7:4: no new variables on left side of :=
Varijable deklarirane bez početne vrijednosti imat će 0 za numeričke tipove, false za Boolean i prazan niz za nizove
konstante
Konstantne varijable su one varijable čija se vrijednost ne može promijeniti kada se jednom dodijeli. Konstanta u programskom jeziku Go deklarirana je pomoću ključne riječi “const”
Napravite datoteku pod nazivom constant.go i sa sljedećim kodom
package main import ("fmt") func main() { const b =10 fmt.Println(b) b = 30 fmt.Println(b) }
Izvrši go run constant.go da vidiš rezultat kao
.constant.go:7:4: cannot assign to b
Za primjere petlje
Petlje se koriste za uzastopno izvršavanje bloka naredbi na temelju uvjeta. Većina programskih jezika nudi 3 vrste petlji – for, while, do while. Ali Go programski jezik podržava samo for petlju.
Sintaksa Golang for petlje je
for initialisation_expression; evaluation_expression; iteration_expression{ // one or more statement }
Inicijalizacijski_izraz izvodi se prvi (i samo jednom) u Golang for petlji.
Zatim se procjenjuje evaluacijski izraz i ako je istinit, izvršava se kod unutar bloka.
Izvršava se id iteration_expression, a valuation_expression se ponovno procjenjuje. Ako je istina, blok iskaza se ponovno izvršava. To će se nastaviti sve dok evaluacijski_izraz ne postane lažan.
Kopirajte donji program u datoteku i pokrenite ga da biste vidjeli petlju Golang za ispis brojeva od 1 do 5
package main import "fmt" func main() { var i int for i = 1; i <= 5; i++ { fmt.Println(i) } }
Izlaz je
1 2 3 4 5
Ako drugo
If else je uvjetna izjava. Sinaks je
if condition{ // statements_1 }else{ // statements_2 }
Ovdje se uvjet procjenjuje i ako je istinit, izvršit će se statement_1, inače će se izvršiti statement_2.
Možete koristiti if naredbu i bez else. Također možete imati lančane if else naredbe. Programi u nastavku objasnit će više o if else.
Izvršite donji program. Provjerava je li broj, x, manji od 10. Ako je tako, ispisat će "x je manji od 10"
package main import "fmt" func main() { var x = 50 if x < 10 { //Executes if x < 10 fmt.Println("x is less than 10") } }
Budući da je vrijednost x veća od 10, naredba unutar uvjeta bloka if neće se izvršiti.
Sada pogledajte donji program. U ovom vodiču za programski jezik Go imamo else blok koji će se izvršiti nakon neuspjeha if evaluacije.
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") } }
Ovaj program će vam dati izlaz
x is greater than or equals 10
U ovom vodiču za Go, vidjet ćemo program s više if else blokova (ulančanih if else). Izvršite Go primjer u nastavku. Provjerava je li broj manji od 10, između 10-90 ili veći od 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") } }
Ovdje prvo if uvjet provjerava je li x manji od 10 i nije. Dakle, provjerava sljedeći uvjet (else if) je li između 10 i 90, što je također lažno. Dakle, tada izvršava blok pod odjeljkom else koji daje izlaz
x is greater than 90
Prekidač
Switch je još jedna uvjetna izjava. Naredbe Switch procjenjuju izraz i rezultat se uspoređuje sa skupom dostupnih vrijednosti (slučaja). Nakon što se pronađe podudaranje, izvršavaju se naredbe povezane s tim podudaranjem (slučajem). Ako se ne pronađe podudaranje, ništa se neće izvršiti. Također možete dodati zadani slučaj za promjenu koji će se izvršiti ako se ne pronađu druga podudaranja. Sintaksa prekidača je
switch expression { case value_1: statements_1 case value_2: statements_2 case value_n: statements_n default: statements_default }
Ovdje se vrijednost izraza uspoređuje s vrijednostima u svakom slučaju. Nakon što se pronađe podudaranje, izvršavaju se naredbe pridružene tom slučaju. Ako se ne pronađe podudaranje, izvršavaju se naredbe u zadanom odjeljku.
Izvršite donji 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") } }
Dobit ćete izlaz kao
Sum is 3
Promijenite vrijednost a i b na 3 i rezultat će biti
Printing default
Također možete imati više vrijednosti u malim i velikim slovima tako da ih odvojite zarezom.
nizovi
Niz predstavlja niz elemenata iste vrste fiksne veličine. Ne možete imati polje koje sadrži i cijeli broj i znakove. Ne možete promijeniti veličinu niza nakon što definirate veličinu.
Sintaksa za deklariranje niza je
var arrayname [size] type
Svakom elementu polja može se dodijeliti vrijednost pomoću sintakse
arrayname [index] = value
Indeks niza počinje od 0 do veličine-1.
Možete dodijeliti vrijednosti elementima niza tijekom deklaracije pomoću sintakse
arrayname := [size] type {value_0,value_1,…,value_size-1}
Također možete zanemariti parametar veličine dok deklarirate polje s vrijednostima zamjenom veličine s ... a prevodilac će iz broja vrijednosti pronaći duljinu. Sintaksa je
arrayname := […] type {value_0,value_1,…,value_size-1}
Duljinu niza možete pronaći pomoću sintakse
len(arrayname)
Izvršite Go primjer u nastavku da biste razumjeli niz
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]) }
Izlaz
Two 3 [One Two Three] [1 2 3 4 5] 5
Golang Slice i funkcija dodavanja
Isječak je dio ili segment niza. Ili je to pogled ili djelomični prikaz temeljnog niza na koji pokazuje. Možete pristupiti elementima odsječka koristeći naziv odsječka i broj indeksa baš kao što to činite u nizu. Ne možete promijeniti duljinu niza, ali možete promijeniti veličinu isječka.
Sadržaj isječka zapravo su pokazivači na elemente niza. To znači ako promijenite bilo koji element u odsječku, to će također utjecati na sadržaj temeljnog polja.
Sintaksa za stvaranje odrezaka je
var slice_name [] type = array_name[start:end]
Ovo će stvoriti odsječak pod nazivom slice_name iz niza pod nazivom array_name s elementima na indeksu od početka do kraja-1.
Sada ćemo u ovom Golang vodiču izvršiti donji program. Program će stvoriti isječak iz niza i ispisati ga. Također, možete vidjeti da će izmjena sadržaja u odsječku izmijeniti stvarni niz.
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) }
Ovo će ispisati rezultat kao
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]
Postoje određene funkcije kao što su Golang len, Golang append koje možete primijeniti na rezove
len(slice_name) – vraća duljinu isječka
dodati(naziv_odsječka, vrijednost_1, vrijednost_2) – Golang append koristi se za dodavanje value_1 i value_2 postojećem odsječku.
dodati(slice_nale1,slice_name2…) – dodaje slice_name2 u slice_name1
Izvršite sljedeći 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) }
Izlaz će biti
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]
Program prvo kreira 2 kriške i ispisuje njihovu duljinu. Zatim je pridodao jednu krišku drugoj, a zatim je pridodao niz rezultirajućoj kriški.
Funkcije
Funkcija predstavlja blok iskaza koji obavljaju određeni zadatak. Deklaracija funkcije nam govori naziv funkcije, tip povrata i ulazne parametre. Definicija funkcije predstavlja kod sadržan u funkciji. Sintaksa za deklariranje funkcije je
func function_name(parameter_1 type, parameter_n type) return_type { //statements }
Parametri i povratne vrste su izborni. Također, možete vratiti više vrijednosti iz funkcije.
Sada u ovom Golang vodiču, pokrenimo sljedeći Golang primjer. Ovdje funkcija pod nazivom calc prihvaća 2 broja i izvodi zbrajanje i oduzimanje te vraća obje vrijednosti.
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) }
Izlaz će biti
Sum 25 Diff 5
Paketi
Paketi se koriste za organiziranje koda. U velikom projektu nije moguće napisati kod u jednoj datoteci. Programski jezik Go omogućuje nam organiziranje koda u različitim paketima. To povećava čitljivost koda i mogućnost ponovne upotrebe. Izvršni Go program treba sadržavati paket pod nazivom main, a izvršavanje programa počinje od funkcije pod nazivom main. Možete uvesti druge pakete u naš program koristeći sintaksu
import package_name
Vidjet ćemo i raspravljati u ovom Golang vodiču, kako stvoriti i koristiti pakete u sljedećem Golang primjeru.
Korak 1) Napravite datoteku pod nazivom package_example.go i dodajte donji kod
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) }
U gornjem programu fmt je paket koji nam Go programski jezik daje uglavnom za I/O svrhe. Također, možete vidjeti paket pod nazivom izračun. Unutar main() možete vidjeti zbroj koraka := izračun. Do_add(x,y). To znači da pozivate funkciju Do_add iz izračuna paketa.
Korak 2) Prvo, trebali biste izraditi izračun paketa unutar mape s istim imenom pod src mapom na go. Instalirani put za go može se pronaći iz varijable PATH.
Za mac pronađite put izvršavanjem echo $PATH
Dakle, put je /usr/local/go
Za Windows, pronađite put izvršavanjem echo %GOROOT%
Ovdje je put C:\Idi\
Korak 3) Idite do mape src (/usr/local/go/src za mac i C:\Go\src za Windows). Sada iz koda, naziv paketa je izračun. Go zahtijeva da se paket smjesti u istoimeni direktorij pod src direktorij. Stvorite direktorij pod nazivom izračun u mapi src.
Korak 4) Napravite datoteku pod nazivom calc.go (Možete dati bilo koji naziv, ali naziv paketa u kodu je važan. Ovdje bi to trebao biti izračun) unutar direktorija za izračun i dodajte donji kod
package calculation func Do_add(num1 int, num2 int)(int) { sum := num1 + num2 return sum }
Korak 5) Pokrenite naredbu go install iz direktorija izračuna koji će kompajlirati calc.go.
Korak 6) Sada se vratite na package_example.go i pokrenite go run package_example.go. Izlaz će biti Zbroj 25.
Imajte na umu da naziv funkcije Do_add počinje velikim slovom. To je zato što u Gou ako naziv funkcije počinje velikim slovom, to znači da je drugi programi mogu vidjeti (pristupiti) inače joj drugi programi ne mogu pristupiti. Da je naziv funkcije do_add, tada biste dobili pogrešku
ne može se odnositi na neizvezeni izračun imena.calc..
Odgoditi i složiti odgode
Naredbe defer koriste se za odgodu izvršenja poziva funkcije dok funkcija koja sadrži naredbu defer ne završi izvršenje.
Naučimo ovo na primjeru:
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()") }
Izlaz će biti
Inside the main() Inside the sample()
Ovdje je izvršenje sample() odgođeno dok se ne završi izvršenje funkcije obuhvatanja (main()).
Slaganje defer koristi više naredbi defer. Pretpostavimo da imate više naredbi defer unutar funkcije. Go smješta sve odgođene pozive funkcija u stog, a nakon što se funkcija obuhvata vrati, složene funkcije se izvršavaju u Zadnji ušao prvi izašao (LIFO) redoslijed. To možete vidjeti u donjem primjeru.
Izvršite donji kod
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) }
Izlaz će biti
4 3 2 1
Ovdje se prvo izvršava kod unutar main(), a zatim se odgođeni pozivi funkcija izvršavaju obrnutim redoslijedom, tj. 4, 3,2,1.
upućuje
Prije nego objasnimo pokazivače, prvo ćemo razgovarati o operatoru '&'. Operator '&' koristi se za dobivanje adrese varijable. To znači da će '&a' ispisati memorijsku adresu varijable a.
U ovom Golang vodiču, izvršit ćemo donji program za prikaz vrijednosti varijable i adrese te varijable
package main import "fmt" func main() { a := 20 fmt.Println("Address:",&a) fmt.Println("Value:",a) }
Rezultat će biti
Address: 0xc000078008 Value: 20
Pokazivačka varijabla pohranjuje memorijsku adresu druge varijable. Pokazivač možete definirati pomoću sintakse
var variable_name *type
Zvjezdica (*) predstavlja varijablu koja je pokazivač. Shvatit ćete više izvršavanjem donjeg programa
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)}
Izlaz će biti
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
Strukture
Struktura je korisnički definiran tip podataka koji sam sadrži još jedan element istog ili različitog tipa.
Korištenje strukture je proces od 2 koraka.
Prvo, kreirajte (deklarirajte) tip strukture
Drugo, stvorite varijable tog tipa za pohranu vrijednosti.
Strukture se uglavnom koriste kada želite zajedno pohraniti povezane podatke.
Razmotrite dio podataka o zaposleniku koji sadrži ime, dob i adresu. To možete riješiti na 2 načina
Napravite 3 niza – jedan niz pohranjuje imena zaposlenika, jedan pohranjuje dob i treći pohranjuje dob.
Deklarirajte tip strukture s 3 polja - ime, adresa i dob. Napravite polje tog tipa strukture gdje je svaki element objekt strukture koji ima naziv, adresu i starost.
Prvi pristup nije učinkovit. U ovakvim scenarijima strukture su prikladnije.
Sintaksa za deklariranje strukture je
type structname struct { variable_1 variable_1_type variable_2 variable_2_type variable_n variable_n_type }
Primjer deklaracije strukture je
type emp struct { name string address string age int }
Ovdje se stvara novi korisnički definirani tip pod nazivom emp. Sada možete kreirati varijable tipa emp pomoću sintakse
var variable_name struct_name
Primjer je
var empdata1 emp
Možete postaviti vrijednosti za empdata1 kao
empdata1.name = "John" empdata1.address = "Street-1, Bangalore" empdata1.age = 30
Također možete stvoriti strukturnu varijablu i dodijeliti joj vrijednosti
empdata2 := emp{"Raj", "Building-1, Delhi", 25}
Ovdje morate održavati redoslijed elemenata. Raj će biti mapiran na ime, sljedeći element na adresu, a zadnji na dob.
Izvršite kod u nastavku
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) }
Izlaz
John Raj
Metode (ne funkcije)
Metoda je funkcija s argumentom primatelja. Archistrukturalno, nalazi se između ključne riječi func i naziva metode. Sintaksa metode je
func (variable variabletype) methodName(parameter1 paramether1type) { }
Pretvorimo gornji primjer programa da koristi metode umjesto funkcija.
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 nije objektno orijentirani jezik i nema koncept klase. Metode daju dojam onoga što radite u objektno orijentiranim programima gdje se funkcije klase pozivaju pomoću sintakse objectname.functionname()
Konkurencija
Go podržava istovremeno izvršavanje zadataka. To znači da Go može izvršavati više zadataka istovremeno. Razlikuje se od koncepta paralelizma. U paralelizmu, zadatak se dijeli na male podzadatke i izvršavaju se paralelno. Ali u istodobnosti, više zadataka se izvršava istovremeno. Konkurentnost se postiže u Go-u pomoću Goroutines i Channels.
Goroutines
Goroutine je funkcija koja se može izvoditi istodobno s drugim funkcijama. Obično kada se funkcija pozove, kontrola se prenosi u pozvanu funkciju, a nakon dovršetka njezina izvršenja kontrola se vraća u funkciju poziva. Pozivajuća funkcija tada nastavlja svoje izvršenje. Pozivajuća funkcija čeka da pozvana funkcija dovrši izvršenje prije nego što nastavi s ostatkom naredbi.
Ali u slučaju goroutine, pozivajuća funkcija neće čekati da se dovrši izvršenje pozvane funkcije. Nastavit će se izvršavati sa sljedećim izjavama. Možete imati više gorutina u programu.
Također, glavni program će izaći nakon što završi izvršavanje svojih naredbi i neće čekati završetak pozivanih goroutina.
Goroutine se poziva pomoću ključne riječi go nakon koje slijedi poziv funkcije.
Primjer
go add(x,y)
Razumjet ćete goroutine s Golangovim primjerima u nastavku. Izvršite donji 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") } }
Izlaz će biti
In main In main In main In main In main
Ovdje je glavni program dovršio izvršenje čak i prije početka goroutine. Display() je gorutina koja se poziva pomoću sintakse
go function_name(parameter list)
U gornjem kodu, main() ne čeka da display() završi, a main() je završio svoje izvršenje prije nego što je display() izvršio svoj kod. Dakle, ispis naredbe unutar display() nije ispisan.
Sada modificiramo program da ispisuje i izjave iz display(). Dodajemo vremensku odgodu od 2 sekunde u for petlji main() i odgodu od 1 sekunde u for petlji 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") } }
Izlaz će biti donekle sličan
In display In main In display In display In main In display In display In main In main In main
Ovdje možete vidjeti kako se obje petlje izvršavaju na način koji se preklapa zbog istovremenog izvođenja.
Kanali
Kanali su način na koji funkcije međusobno komuniciraju. Može se smatrati medijem gdje jedna rutina postavlja podatke i pristupa im druga rutina u Golang poslužitelju.
Kanal se može deklarirati pomoću sintakse
channel_variable := make(chan datatype)
Primjer:
ch := make(chan int)
Možete poslati podatke kanalu pomoću sintakse
channel_variable <- variable_name
Primjer
ch <- x
Podatke s kanala možete primati pomoću sintakse
variable_name := <- channel_variable
Primjer
y := <- ch
U gornjim primjerima goroutine na Go jeziku, vidjeli ste da glavni program ne čeka goroutine. Ali to nije slučaj kada su u pitanju kanali. Pretpostavimo da ako goroutine gura podatke u kanal, main() će čekati naredbu koja prima podatke kanala dok ne dobije podatke.
To ćete vidjeti u primjerima Go jezika ispod. Prvo napišite normalnu goroutinu i pogledajte ponašanje. Zatim modificirajte program za korištenje kanala i pogledajte ponašanje.
Izvršite donji 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()") }
Izlaz će biti
Inside main()
Main() je završio izvršenje i izašao prije nego što se izvrši goroutina. Tako se ispis unutar display() nije izvršio.
Sada modificirajte gornji program za korištenje kanala i pogledajte ponašanje.
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) }
Izlaz će biti
Inside display() Inside main() Printing x in main() after taking from channel: 1234
Ovdje se događa main() kada dođe do x := <-ch će čekati podatke na kanalu ch. Display() čeka 5 sekundi, a zatim šalje podatke na kanal ch. Main() nakon primanja podataka s kanala deblokira se i nastavlja s izvršavanjem.
Pošiljatelj koji gura podatke u kanal može obavijestiti primatelje da se više podaci neće dodavati u kanal zatvaranjem kanala. Ovo se uglavnom koristi kada koristite petlju za slanje podataka na kanal. Kanal se može zatvoriti pomoću
close(channel_name)
A na strani primatelja, moguće je provjeriti je li kanal zatvoren korištenjem dodatne varijable tijekom dohvaćanja podataka s kanala korištenjem
variable_name, status := <- channel_variable
Ako je status True to znači da ste primili podatke s kanala. Ako je lažno, to znači da pokušavate čitati sa zatvorenog kanala
Također možete koristiti kanale za komunikaciju između goroutina. Trebate koristiti 2 gorutine – jedna gura podatke u kanal, a druga prima podatke s kanala. Pogledajte donji 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()") }
Ovdje postoje 2 potprograma, jedan gura podatke u kanal, a drugi ispisuje podatke u kanal. Funkcija add_to_channel zbraja brojeve od 0 do 9 i zatvara kanal. Istovremeno funkcija fetch_from_channel čeka na
x, zastavica := <- ch i kada podaci postanu dostupni, ispisuje ih. Izlazi kada je zastavica lažna što znači da je kanal zatvoren.
Čekanje u main() je dano da se spriječi izlazak iz main() dok goroutine ne završe izvršenje.
Izvršite kod i pogledajte izlaz kao
Read data Send data 0 1 2 3 4 5 6 7 8 9 Empty channel Inside main()
odabrati
Select se može promatrati kao switch izjava koja radi na kanalima. Ovdje će naredbe case biti operacija kanala. Obično će svaki iskaz slučaja biti pokušaj čitanja s kanala. Kada je bilo koji slučaj spreman (kanal je pročitan), tada se izvršava naredba povezana s tim slučajem. Ako je spremno više slučajeva, odabrat će slučajni odabir. Možete imati zadani slučaj koji se izvršava ako nijedan od slučajeva nije spreman.
Pogledajmo donji kod
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) } }
Izvršenje gornjeg programa dat će izlaz:
from data2()
Ovdje naredba select čeka da podaci budu dostupni u bilo kojem od kanala. Data2() dodaje podatke u kanal nakon mirovanja od 2 sekunde što će uzrokovati izvršenje drugog slučaja.
Dodajte zadani slučaj odabiru u istom programu i pogledajte izlaz. Ovdje, po dostizanju odabranog bloka, ako nijedan slučaj nema spremne podatke na kanalu, izvršit će zadani blok bez čekanja da podaci budu dostupni na bilo kojem kanalu.
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") } }
Ovaj program će dati rezultat:
Default case executed
To je zato što kada je dosegnut blok odabira, nijedan kanal nije imao podatke za čitanje. Dakle, zadani slučaj je izvršen.
muteksi
Mutex je skraćenica za međusobno isključivanje. Mutex se koristi kada ne želite dopustiti da resursu pristupi više potprograma u isto vrijeme. Mutex ima 2 metode – zaključavanje i otključavanje. Mutex se nalazi u paketu za sinkronizaciju. Dakle, morate uvesti paket sinkronizacije. Naredbe koje se moraju međusobno isključivo izvršiti mogu se smjestiti unutar mutex.Lock() i mutex.Unlock().
Naučimo mutex na primjeru koji broji koliko se puta petlja izvodi. U ovom programu očekujemo da će rutina pokrenuti petlju 10 puta, a broj se pohranjuje u zbroju. Pozivate ovu rutinu 3 puta tako da bi ukupni broj trebao biti 30. Broj je pohranjen u globalnoj varijabli count.
Prvo, pokrećete program bez mutexa
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) }
Pogledajte rezultat
Count after i=1 Count: 11 Count after i=3 Count: 12 Count after i=2 Count: 13 Final Count: 13
Rezultat bi mogao biti drugačiji kada ga izvršite, ali konačni rezultat neće biti 30.
Ovdje se događa da 3 gorutine pokušavaju povećati broj petlji pohranjen u varijabli count. Pretpostavimo da je u ovom trenutku broj 5 i goroutine1 će povećati broj na 6. Glavni koraci uključuju
Kopiraj broj u temp
Povećanje temp
Pohranite temperaturu natrag za brojanje
Pretpostavimo ubrzo nakon izvođenja koraka 3 od strane goroutine1; neka druga goroutina može imati staru vrijednost, recimo 3 radi gore navedene korake i pohranjuje 4 natrag, što je pogrešno. Ovo se može spriječiti korištenjem mutexa koji uzrokuje čekanje drugih rutina kada jedna rutina već koristi varijablu.
Sada ćete pokrenuti program s mutexom. Ovdje se gore navedena 3 koraka izvode u mutexu.
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) }
Sada će izlaz biti
Count after i=3 Count: 21 Count after i=2 Count: 28 Count after i=1 Count: 30 Final Count: 30
Ovdje dobivamo očekivani rezultat kao konačni izlaz. Budući da se iskazi čitanja, inkrementiranja i povratnog pisanja brojanja izvode u mutexu.
Rukovanje pogreškama
Pogreške su nenormalni uvjeti poput zatvaranja datoteke koja nije otvorena, otvaranja datoteke koja ne postoji itd. Funkcije obično vraćaju pogreške kao posljednju vraćenu vrijednost.
Primjer u nastavku objašnjava više o pogrešci.
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") }
Izlaz će biti:
open /invalid.txt: no such file or directory
Ovdje smo pokušali otvoriti nepostojeću datoteku, a ona je vratila pogrešku varijabli er. Ako je datoteka valjana, pogreška će biti nula
Prilagođene pogreške
Pomoću ove značajke možete kreirati prilagođene pogreške. To se radi korištenjem New() paketa pogrešaka. Ponovno ćemo napisati gornji program kako bismo iskoristili prilagođene pogreške.
Pokrenite donji 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) } }
Izlaz će biti:
Custom error message:File name is wrong
Ovdje area() vraća površinu kvadrata. Ako je unos manji od 1 tada area() vraća poruku o pogrešci.
Čitanje datoteka
Datoteke se koriste za pohranu podataka. Go nam omogućuje čitanje podataka iz datoteka
Prvo stvorite datoteku, data.txt, u vašem trenutnom direktoriju sa sadržajem ispod.
Line one Line two Line three
Sada pokrenite donji program da vidite kako ispisuje sadržaj cijele datoteke kao izlaz
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)) }
Ovdje podaci, err := ioutil.ReadFile(“data.txt”) čitaju podatke i vraćaju niz bajtova. Tijekom ispisa pretvara se u string format.
Pisanje datoteka
To ćete vidjeti s programom
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 } }
Ovdje se stvara datoteka, test.txt. Ako datoteka već postoji, tada se sadržaj datoteke skraćuje. Writeline() se koristi za pisanje sadržaja u datoteku. Nakon toga ste zatvorili datoteku koristeći Close().
Cheat Sheet
U ovom vodiču za Go obradili smo,
Tema | Description | Sintaksa |
---|---|---|
Osnovne vrste | Numerički, string, bool | |
Varijable | Deklarirajte i dodijelite vrijednosti varijablama | var variable_name tip var ime_varijable tip = vrijednost var ime_varijable1, ime_varijable2 = vrijednost1, vrijednost2 ime_varijable := vrijednost |
konstante | Varijable čija se vrijednost ne može promijeniti kada se jednom dodijeli | const varijabla = vrijednost |
Za petlju | Izvršavanje naredbi u petlji. | za inicijalizacijski_izraz; evaluacijski_izraz; iteracijski_izraz{ // jedna ili više izjava } |
Ako drugo | To je uvjetna izjava | ako uvjet{ // izjave_1 } Else { // izjave_2 } |
prebaciti | Uvjetni iskaz s više slučajeva | prebaci izraz { case value_1: izjave_1 case value_2: izjave_2 case value_n: izjave_n zadana: izjave_zadano } |
Poredak | Slijed elemenata iste vrste fiksne veličine | naziv niza := [veličina] tip {vrijednost_0,vrijednost_1,…,veličina_vrijednosti-1} |
Kriška | Dio ili segment niza | var slice_name [] tip = array_name[početak:kraj] |
Funkcije | Blok naredbi koji izvršava određeni zadatak | func naziv_funkcije(tip parametra_1, tip parametra_n) return_type { //izjave } |
Paketi | Koriste se za organiziranje koda. Povećava čitljivost koda i mogućnost ponovne upotrebe | import package_nam |
Odgoditi | Odgađa izvršenje funkcije dok funkcija koja sadrži ne završi s izvršenjem | defer function_name(parameter_list) |
upućuje | Pohranjuje memorijsku adresu druge varijable. | var ime_varijable *tip |
Struktura | Korisnički definiran tip podataka koji sam sadrži još jedan element istog ili različitog tipa | upišite structname struct { varijabla_1 vrsta_varijable_1 varijabla_2 vrsta_varijable_2 varijabla_n vrsta_varijable_n } |
Metode | Metoda je funkcija s argumentom primatelja | func (varijabla tip varijable) methodName(parameter_list) { } |
Goroutine | Funkcija koja se može izvoditi istodobno s drugim funkcijama. | idi naziv_funkcije(popis_parametara) |
Kanal | Način na koji funkcije međusobno komuniciraju. Medij na koji jedna rutina postavlja podatke i pristupa mu druga rutina. | Proglasiti: ch := make(chan int) Pošalji podatke na kanal: varijabla_kanala <- naziv_varijable Primi sa kanala: naziv_varijable := <- varijabla_kanala |
odabrati | Izjava Switch koja radi na kanalima. Izjave slučaja bit će operacija kanala. Kada je bilo koji od kanala spreman s podacima, tada se izvršava naredba povezana s tim slučajem | Izaberi { slučaj x := <-chan1: fmt.Println(x) case y := <-chan2: fmt.Println(y) } |
muteksi | Mutex se koristi kada ne želite dopustiti da resursu pristupi više potprograma u isto vrijeme. Mutex ima 2 metode – zaključavanje i otključavanje | mutex.Lock() //izjave mutex.Otključaj(). |
Čitaj datoteke | Čita podatke i vraća niz bajtova. | Podaci, pogreška := ioutil.ReadFile(naziv datoteke) |
Napiši datoteku | Zapisuje podatke u datoteku | l, pogreška := f.WriteString(text_to_write) |