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)