Samouczek Golang

Co to jest Go?

Go (znany rรณwnieลผ jako Golang) jest jฤ™zykiem programowania open source opracowanym przez Google. Jest to statycznie typowany kompilowany jฤ™zyk. Go obsล‚uguje programowanie wspรณล‚bieลผne, tzn. pozwala na jednoczesne uruchamianie wielu procesรณw. Jest to moลผliwe dziฤ™ki kanaล‚om, goroutines itp. Jฤ™zyk Go ma zbieranie ล›mieci, ktรณre samo zarzฤ…dza pamiฤ™ciฤ… i pozwala na opรณลบnione wykonywanie funkcji.

W tym samouczku Learn Go Language nauczymy siฤ™ wszystkich podstaw jฤ™zyka Golang.

Jak pobraฤ‡ i zainstalowaฤ‡ GO

Krok 1) Iล›ฤ‡ do https://golang.org/dl/. Pobierz plik binarny dla swojego systemu operacyjnego.

Krok 2) Double kliknij instalator i kliknij Uruchom.

Krok 3) Kliknij Dalej

Krok 4) Wybierz folder instalacyjny i kliknij Dalej.

Krok 5) Kliknij Zakoล„cz po zakoล„czeniu instalacji.

Krok 6) Po zakoล„czeniu instalacji moลผesz to sprawdziฤ‡, otwierajฤ…c terminal i wpisujฤ…c

go version

Spowoduje to wyล›wietlenie zainstalowanej wersji go

Twรณj program First Go โ€“ Go Hello World!

Utwรณrz folder o nazwie studyGo. W tym samouczku jฤ™zyka Go utworzymy nasze programy w tym folderze. Pliki Go sฤ… tworzone z rozszerzeniem .wybraฤ‡ siฤ™. Moลผesz uruchamiaฤ‡ programy Go, uลผywajฤ…c skล‚adni

go run <filename>

Utwรณrz plik o nazwie First.go, dodaj do niego poniลผszy kod i zapisz

package main
import ("fmt")

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

Przejdลบ do tego folderu w terminalu. Uruchom program za pomocฤ… polecenia

idลบ najpierw pobiegnij. idลบ

Moลผesz zobaczyฤ‡ wydruk wyjล›ciowy

Hello World! This is my first Go program

Omรณwmy teraz powyลผszy program.

package main โ€“ Kaลผdy program Go Language powinien zaczynaฤ‡ siฤ™ od nazwy pakietu. Go pozwala nam uลผywaฤ‡ pakietรณw w innych programach go, a tym samym wspiera ponowne wykorzystanie kodu. Wykonanie programu Go rozpoczyna siฤ™ od kodu znajdujฤ…cego siฤ™ w pakiecie o nazwie main.

import fmt โ€“ importuje pakiet fmt. Pakiet ten implementuje funkcje we/wy.

func main() โ€“ Jest to funkcja, od ktรณrej rozpoczyna siฤ™ wykonywanie programu. Funkcja gล‚รณwna powinna byฤ‡ zawsze umieszczona w pakiecie gล‚รณwnym. Pod funkcjฤ… main() moลผesz wpisaฤ‡ kod wewnฤ…trz { }.

fmt.Println โ€“ Spowoduje wydrukowanie tekstu na ekranie za pomocฤ… funkcji Println fmt.

Uwaga: w poniลผszych sekcjach tego samouczka Go, gdy wspominasz o wykonaniu/uruchomieniu kodu, oznacza to zapisanie kodu w pliku z rozszerzeniem .go i uruchomienie go przy uลผyciu skล‚adni

    go run <filename>

Typy danych

Typy (typy danych) reprezentujฤ… typ wartoล›ci przechowywanej w zmiennej, typ wartoล›ci zwracanej przez funkcjฤ™ itp.

Istniejฤ… trzy podstawowe typy w jฤ™zyku Go

Typy liczbowe โ€“ Reprezentujฤ… wartoล›ci liczbowe, w tym liczby caล‚kowite, zmiennoprzecinkowe i wartoล›ci zespolone. Rรณลผne typy liczbowe to:

int8 โ€“ 8-bitowe liczby caล‚kowite ze znakiem.

int16 โ€“ 16-bitowe liczby caล‚kowite ze znakiem.

int32 โ€“ 32-bitowe liczby caล‚kowite ze znakiem.

int64 โ€“ 64-bitowe liczby caล‚kowite ze znakiem.

uint8 โ€“ 8-bitowe liczby caล‚kowite bez znaku.

uint16 โ€“ 16-bitowe liczby caล‚kowite bez znaku.

uint32 โ€“ 32-bitowe liczby caล‚kowite bez znaku.

uint64 โ€“ 64-bitowe liczby caล‚kowite bez znaku.

float32 โ€“ 32-bitowe liczby zmiennoprzecinkowe.

float64 โ€“ 64-bitowe liczby zmiennoprzecinkowe.

complex64 โ€“ ma float32 czฤ™ล›ci rzeczywistej i urojonej.

complex128 โ€“ ma float32 czฤ™ล›ci rzeczywistej i urojonej.

Rodzaje ciฤ…gรณw โ€“ Reprezentuje sekwencjฤ™ bajtรณw (znakรณw). Moลผesz wykonywaฤ‡ rรณลผne operacje na ciฤ…gach, takie jak ล‚ฤ…czenie ciฤ…gรณw, wyodrฤ™bnianie podciฤ…gรณw itp.

Typy logiczne โ€“ Reprezentuje 2 wartoล›ci, prawdฤ™ lub faล‚sz.

Interfejs Golanga

Interfejs Golanga to zbiรณr sygnatur metod uลผywanych przez Type do implementowania zachowania obiektรณw. Gล‚รณwnym celem interfejsu Golang jest dostarczanie sygnatur metod z nazwami, argumentami i typami zwracanych wartoล›ci. Zadeklarowanie i zaimplementowanie metody zaleลผy od typu. Interfejs w jฤ™zyku Golang moลผna zadeklarowaฤ‡ za pomocฤ… sล‚owa kluczowego โ€žinterfejsโ€.

Zmienne

Zmienne wskazujฤ… lokalizacjฤ™ pamiฤ™ci, w ktรณrej przechowywana jest pewna wartoล›ฤ‡. Parametr typu (w poniลผszej skล‚adni) reprezentuje typ wartoล›ci, ktรณra moลผe byฤ‡ przechowywana w lokalizacji pamiฤ™ci.

Zmiennฤ… moลผna zadeklarowaฤ‡ za pomocฤ… skล‚adni

    var <variable_name> <type>

Po zadeklarowaniu zmiennej typu moลผesz przypisaฤ‡ zmiennฤ… do dowolnej wartoล›ci tego typu.

Moลผesz takลผe nadaฤ‡ zmiennej wartoล›ฤ‡ poczฤ…tkowฤ… podczas samej deklaracji, uลผywajฤ…c

    var <variable_name> <type> = <value>

Jeล›li zadeklarujesz zmiennฤ… z wartoล›ciฤ… poczฤ…tkowฤ…, wywnioskowaj typ zmiennej z typu przypisanej wartoล›ci. Moลผesz wiฤ™c pominฤ…ฤ‡ typ podczas deklaracji, uลผywajฤ…c skล‚adni

    var <variable_name> = <value>

Moลผesz takลผe zadeklarowaฤ‡ wiele zmiennych za pomocฤ… skล‚adni

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

Poniลผszy program w tym samouczku Go zawiera kilka przykล‚adรณw deklaracji zmiennych w jฤ™zyku Golang

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

Dane wyjล›ciowe bฤ™dฤ…

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

Jฤ™zyk Go zapewnia takลผe ล‚atwy sposรณb deklarowania wartoล›ci zmiennych poprzez pominiฤ™cie sล‚owa kluczowego var using

    <variable_name> := <value>

Zauwaลผ, ลผe uลผyล‚eล› := zamiast =. Nie moลผesz uลผyฤ‡ := tylko do przypisania wartoล›ci do zmiennej, ktรณra jest juลผ zadeklarowana. := sล‚uลผy do deklarowania i przypisywania wartoล›ci.

Utwรณrz plik o nazwie assign.go z nastฤ™pujฤ…cym kodem

package main
import ("fmt")

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

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

Wykonaj polecenie go run sign.go, aby zobaczyฤ‡ wynik jako

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

Zmienne zadeklarowane bez wartoล›ci poczฤ…tkowej bฤ™dฤ… miaล‚y wartoล›ฤ‡ 0 dla typรณw numerycznych, wartoล›ฤ‡ false dla typรณw logicznych i pusty ciฤ…g znakรณw dla ciฤ…gรณw

Staล‚e

Zmienne staล‚e to te zmienne, ktรณrych wartoล›ci nie moลผna zmieniฤ‡ po przypisaniu. Staล‚a w jฤ™zyku programowania Go jest deklarowana za pomocฤ… sล‚owa kluczowego โ€žconstโ€

Utwรณrz plik o nazwie constant.go i uลผyj nastฤ™pujฤ…cego kodu

package main
import ("fmt")

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

Wykonaj idลบ, uruchom staล‚ฤ….go, aby zobaczyฤ‡ wynik jako

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

Przykล‚ady pฤ™tli

Pฤ™tle sล‚uลผฤ… do wielokrotnego wykonywania bloku instrukcji w oparciu o warunek. Wiฤ™kszoล›ฤ‡ jฤ™zykรณw programowania udostฤ™pnia 3 rodzaje pฤ™tli โ€“ for, while, do while. Ale jฤ™zyk programowania Go obsล‚uguje tylko pฤ™tlฤ™ for.

Skล‚adnia pฤ™tli for Golang jest nastฤ™pujฤ…ca

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

Wyraลผenie_inicjalizacji jest wykonywane jako pierwsze (i tylko raz) w pฤ™tli for Golang.

Nastฤ™pnie oceniane jest wyraลผenie_oceny i jeล›li jest prawdziwe, wykonywany jest kod znajdujฤ…cy siฤ™ w bloku.

Wykonywany jest identyfikator iteracji_wyraลผenia, a ocena_wyraลผenia jest oceniana ponownie. Jeล›li to prawda, blok instrukcji zostanie wykonany ponownie. Bฤ™dzie to trwaล‚o, dopรณki wyraลผenie_oceny nie stanie siฤ™ faล‚szywe.

Skopiuj poniลผszy program do pliku i uruchom go, aby zobaczyฤ‡ pฤ™tlฤ™ for jฤ™zyka Go drukujฤ…cฤ… liczby od 1 do 5

package main
import "fmt"

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

Wyjล›cie to

1
2
3
4
5

Jeล›li inaczej

Jeล›li else jest instrukcjฤ… warunkowฤ…. Synaks jest

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

Tutaj oceniany jest warunek i jeล›li jest prawdziwy, wykonane zostanฤ… instrukcje_1, w przeciwnym razie wykonane zostanฤ… instrukcje_2.

Moลผesz uลผyฤ‡ instrukcji if rรณwnieลผ bez else. Moลผna takลผe poล‚ฤ…czyฤ‡ instrukcje if else. Poniลผsze programy wyjaล›niฤ… wiฤ™cej na temat if else.

Wykonaj poniลผszy program. Sprawdza, czy liczba x jest mniejsza niลผ 10. Jeล›li tak, wyล›wietli โ€žx jest mniejsze niลผ 10โ€

package main
import "fmt"

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

Tutaj, poniewaลผ wartoล›ฤ‡ x jest wiฤ™ksza niลผ 10, instrukcja if w warunku bloku nie zostanie wykonana.

Teraz spรณjrz na poniลผszy program. W tym samouczku dotyczฤ…cym jฤ™zyka programowania Go mamy blok else, ktรณry zostanie wykonany w przypadku niepowodzenia oceny if.

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

Ten program wyล›wietli dane wyjล›ciowe

x is greater than or equals 10

W tym samouczku Go zobaczymy program z wieloma blokami if else (poล‚ฤ…czonymi ล‚aล„cuchowo if else). Wykonaj poniลผszy przykล‚ad Go. Sprawdza, czy liczba jest mniejsza niลผ 10, mieล›ci siฤ™ w przedziale 10-90 lub jest wiฤ™ksza niลผ 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")
    }
}

Tutaj najpierw warunek if sprawdza, czy x jest mniejsze niลผ 10 i tak nie jest. Sprawdza zatem, czy nastฤ™pny warunek (else if) mieล›ci siฤ™ w przedziale od 10 do 90, co rรณwnieลผ jest faล‚szywe. Nastฤ™pnie wykonuje blok w sekcji else, ktรณry daje wynik

x is greater than 90

Przeล‚ฤ…cznik

Switch to kolejna instrukcja warunkowa. Instrukcje Switch oceniajฤ… wyraลผenie, a wynik jest porรณwnywany z zestawem dostฤ™pnych wartoล›ci (przypadkรณw). Po znalezieniu dopasowania wykonywane sฤ… instrukcje powiฤ…zane z tym dopasowaniem (przypadkiem). Jeล›li nie zostanie znalezione ลผadne dopasowanie, nic nie zostanie wykonane. Moลผesz takลผe dodaฤ‡ domyล›lny przypadek do przeล‚ฤ…czenia, ktรณry zostanie wykonany, jeล›li nie zostanฤ… znalezione ลผadne inne dopasowania. Skล‚adnia przeล‚ฤ…cznika jest nastฤ™pujฤ…ca

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

Tutaj wartoล›ฤ‡ wyraลผenia jest porรณwnywana z wartoล›ciami w kaลผdym przypadku. Po znalezieniu dopasowania wykonywane sฤ… instrukcje powiฤ…zane z tym przypadkiem. Jeล›li nie zostanie znalezione ลผadne dopasowanie, wykonywane sฤ… instrukcje z sekcji domyล›lnej.

Wykonaj poniลผszy 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")
    }
}

Otrzymasz dane wyjล›ciowe jako

Sum is 3		

Zmieล„ wartoล›ฤ‡ a i b na 3, a wynik bฤ™dzie taki

Printing default

W przypadku moลผna rรณwnieลผ umieล›ciฤ‡ wiele wartoล›ci, oddzielajฤ…c je przecinkiem.

Tablice

Array reprezentuje staล‚y rozmiar, nazwanฤ… sekwencjฤ™ elementรณw tego samego typu. Nie moลผna mieฤ‡ tablicy zawierajฤ…cej zarรณwno liczby caล‚kowite, jak i znaki. Po zdefiniowaniu rozmiaru nie moลผna zmieniฤ‡ rozmiaru tablicy.

Skล‚adnia deklarowania tablicy jest nastฤ™pujฤ…ca

var arrayname [size] type

Kaลผdemu elementowi tablicy moลผna przypisaฤ‡ wartoล›ฤ‡ za pomocฤ… skล‚adni

arrayname [index] = value

Indeks tablicy zaczyna siฤ™ od 0 do rozmiaru-1.

Moลผesz przypisywaฤ‡ wartoล›ci do elementรณw tablicy podczas deklaracji, uลผywajฤ…c skล‚adni

arrayname := [size] type {value_0,value_1,โ€ฆ,value_size-1} 

Moลผesz takลผe zignorowaฤ‡ parametr size podczas deklarowania tablicy z wartoล›ciami, zastฤ™pujฤ…c size przez ... a kompilator znajdzie dล‚ugoล›ฤ‡ na podstawie liczby wartoล›ci. Skล‚adnia jest

arrayname :=  [โ€ฆ] type {value_0,value_1,โ€ฆ,value_size-1}

Dล‚ugoล›ฤ‡ tablicy moลผna znaleลบฤ‡, korzystajฤ…c ze skล‚adni

len(arrayname)

Wykonaj poniลผszy przykล‚ad Go, aby zrozumieฤ‡ tablicฤ™

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

Wydajnoล›ฤ‡

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

Funkcja krojenia i doล‚ฤ…czania Golanga

Plasterek to czฤ™ล›ฤ‡ lub segment tablicy. Lub jest to widok lub czฤ™ล›ciowy widok podstawowej tablicy, na ktรณrฤ… wskazuje. Dostฤ™p do elementรณw plasterka moลผna uzyskaฤ‡, uลผywajฤ…c nazwy plasterka i numeru indeksu, tak samo jak w przypadku tablicy. Nie moลผesz zmieniฤ‡ dล‚ugoล›ci tablicy, ale moลผesz zmieniฤ‡ rozmiar plasterka.

Zawartoล›ฤ‡ plasterka jest w rzeczywistoล›ci wskaลบnikami do elementรณw tablicy. To znaczy jeล›li zmienisz dowolny element w plasterku, bฤ™dzie to miaล‚o wpล‚yw rรณwnieลผ na zawartoล›ฤ‡ tablicy.

Skล‚adnia tworzenia plasterka jest nastฤ™pujฤ…ca

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

Spowoduje to utworzenie plasterka o nazwie nazwa_plasterka z tablicy o nazwie nazwa_tablicy z elementami od poczฤ…tku do koล„ca indeksu -1.

Teraz w tym samouczku Golang wykonamy poniลผszy program. Program utworzy wycinek z tablicy i wydrukuje go. Moลผesz takลผe zobaczyฤ‡, ลผe modyfikacja zawartoล›ci wycinka spowoduje modyfikacjฤ™ rzeczywistej tablicy.

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

Spowoduje to wydrukowanie wyniku jako

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]

Istniejฤ… pewne funkcje, takie jak Golang len, Golang append, ktรณre moลผna zastosowaฤ‡ na plasterkach

len(nazwa_kawaล‚ka) โ€“ zwraca dล‚ugoล›ฤ‡ plasterka

append(nazwa_kawaล‚ka, wartoล›ฤ‡_1, wartoล›ฤ‡_2) โ€“ Doล‚ฤ…czenie Golanga sล‚uลผy do doล‚ฤ…czenia wartoล›ci_1 i wartoล›ci_2 do istniejฤ…cego plasterka.

append(kawaล‚ek_nale1,nazwa_kawaล‚ka2โ€ฆ) โ€“ doล‚ฤ…cza nazwa_plasterka2 do nazwa_plasterku1

Uruchom nastฤ™pujฤ…cy 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)
}

Dane wyjล›ciowe bฤ™dฤ…

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 najpierw tworzy 2 plasterki i drukuje ich dล‚ugoล›ฤ‡. Nastฤ™pnie doล‚ฤ…czyล‚ jeden plasterek do drugiego, a nastฤ™pnie doล‚ฤ…czyล‚ ciฤ…g do powstaล‚ego plasterka.

Funkcje

Funkcja reprezentuje blok instrukcji, ktรณry wykonuje okreล›lone zadanie. Deklaracja funkcji podaje nam nazwฤ™ funkcji, typ zwracanej wartoล›ci i parametry wejล›ciowe. Definicja funkcji reprezentuje kod zawarty w funkcji. Skล‚adnia deklarowania funkcji jest nastฤ™pujฤ…ca

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

Parametry i typy zwracane sฤ… opcjonalne. Moลผesz takลผe zwrรณciฤ‡ wiele wartoล›ci z funkcji.

Teraz w tym samouczku Golanga, uruchommy nastฤ™pujฤ…cy przykล‚ad Golanga. Tutaj funkcja o nazwie calc zaakceptuje 2 liczby i wykona dodawanie i odejmowanie i zwrรณci obie wartoล›ci.

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

Dane wyjล›ciowe bฤ™dฤ…

Sum 25
Diff 5

Pakiety

Pakiety sล‚uลผฤ… do organizowania kodu. W duลผym projekcie nie da siฤ™ napisaฤ‡ kodu w jednym pliku. Jฤ™zyk programowania Go pozwala nam organizowaฤ‡ kod w rรณลผnych pakietach. Zwiฤ™ksza to czytelnoล›ฤ‡ kodu i moลผliwoล›ฤ‡ jego ponownego uลผycia. Wykonywalny program Go powinien zawieraฤ‡ pakiet o nazwie main, a wykonywanie programu rozpoczyna siฤ™ od funkcji o nazwie main. Moลผesz zaimportowaฤ‡ inne pakiety w naszym programie za pomocฤ… skล‚adni

import package_name

W tym samouczku jฤ™zyka Go zobaczymy i omรณwimy, jak tworzyฤ‡ i uลผywaฤ‡ pakietรณw w poniลผszym przykล‚adzie jฤ™zyka Go.

Krok 1) Utwรณrz plik o nazwie package_example.go i dodaj poniลผszy 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) 
}

W powyลผszym programie fmt jest pakietem, ktรณry jฤ™zyk programowania Go udostฤ™pnia nam gล‚รณwnie do celรณw we/wy. Moลผesz takลผe zobaczyฤ‡ pakiet o nazwie obliczenie. Wewnฤ…trz funkcji main() moลผesz zobaczyฤ‡ sumฤ™ krokรณw := obliczenia.Do_add(x,y). Oznacza to, ลผe wywoล‚ujesz funkcjฤ™ Do_add z obliczenia pakietu.

Krok 2) Najpierw powinieneล› utworzyฤ‡ kalkulacjฤ™ pakietu w folderze o tej samej nazwie w folderze src. Zainstalowanฤ… ล›cieลผkฤ™ go moลผna znaleลบฤ‡ w zmiennej PATH.

W przypadku komputerรณw Mac znajdลบ ล›cieลผkฤ™, wykonujฤ…c echo $PATH

Zatem ล›cieลผka to /usr/local/go

W przypadku systemu Windows znajdลบ ล›cieลผkฤ™, wykonujฤ…c polecenie echo %GOROOT%

Tutaj ล›cieลผka to C:\Go\

Krok 3) Przejdลบ do folderu src (/usr/local/go/src dla komputerรณw Mac i C:\Go\src dla systemรณw Windows). Teraz w kodzie nazwa pakietu to accounting. Go wymaga, aby pakiet zostaล‚ umieszczony w katalogu o tej samej nazwie w katalogu src. Utwรณrz katalog o nazwie accounting w folderze src.

Krok 4) Utwรณrz plik o nazwie calc.go (moลผesz podaฤ‡ dowolnฤ… nazwฤ™, ale nazwa pakietu w kodzie ma znaczenie. Tutaj powinny byฤ‡ obliczenia) w katalogu obliczeล„ i dodaj poniลผszy kod

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

Krok 5) Uruchom polecenie go install z katalogu obliczeล„, ktรณry skompiluje plik calc.go.

Krok 6) Teraz wrรณฤ‡ do package_example.go i uruchom go run package_example.go. Wynikiem bฤ™dzie Suma 25.

Naleลผy pamiฤ™taฤ‡, ลผe nazwa funkcji Do_add zaczyna siฤ™ od duลผej litery. Dzieje siฤ™ tak dlatego, ลผe w Go, jeล›li nazwa funkcji zaczyna siฤ™ z duลผej litery, oznacza to, ลผe inne programy mogฤ… jฤ… zobaczyฤ‡ (uzyskaฤ‡ do niej dostฤ™p), w przeciwnym razie inne programy nie bฤ™dฤ… miaล‚y do โ€‹โ€‹niej dostฤ™pu. Gdyby nazwa funkcji brzmiaล‚a do_add , wystฤ…piล‚by bล‚ฤ…d

nie moลผe odwoล‚ywaฤ‡ siฤ™ do niewyeksportowanej nazwy obliczeล„.calc..

Odroczenie i ukล‚adanie w stosy

Instrukcje Defer sล‚uลผฤ… do odroczenia wykonania wywoล‚ania funkcji do czasu zakoล„czenia wykonywania funkcji zawierajฤ…cej instrukcjฤ™ Defer.

Nauczmy siฤ™ tego na przykล‚adzie:

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

Dane wyjล›ciowe bฤ™dฤ…

Inside the main()
Inside the sample()

W tym przypadku wykonanie prรณbki() jest odroczone do czasu zakoล„czenia wykonywania otaczajฤ…cej jฤ… funkcji (main()).

Odroczenie stosowe wykorzystuje wiele instrukcji odroczenia. Zaล‚รณลผmy, ลผe wewnฤ…trz funkcji znajduje siฤ™ wiele instrukcji odroczenia. Go umieszcza wszystkie odroczone wywoล‚ania funkcji na stosie, a gdy funkcja otaczajฤ…ca powrรณci, funkcje uล‚oลผone w stos zostanฤ… wykonane w Zamรณwienie โ€žostatnie weszล‚o, pierwsze wyszล‚oโ€ (LIFO). Moลผna to zobaczyฤ‡ na poniลผszym przykล‚adzie.

Wykonaj poniลผszy 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)
}

Dane wyjล›ciowe bฤ™dฤ…

4
3
2
1			

Tutaj najpierw wykonywany jest kod wewnฤ…trz funkcji main(), a nastฤ™pnie odroczone wywoล‚ania funkcji sฤ… wykonywane w odwrotnej kolejnoล›ci, tj. 4, 3,2,1.

wskaลบniki

Zanim wyjaล›nimy wskaลบniki, omรณwmy najpierw operator '&'. Operator '&' jest uลผywany do uzyskania adresu zmiennej. Oznacza to, ลผe '&a' wydrukuje adres pamiฤ™ci zmiennej a.

W tym samouczku Golang uruchomimy poniลผszy program, aby wyล›wietliฤ‡ wartoล›ฤ‡ zmiennej i adres tej zmiennej

package main
import "fmt"

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

Wynik bฤ™dzie

Address: 0xc000078008
Value: 20

Zmienna wskaลบnikowa przechowuje adres pamiฤ™ci innej zmiennej. Wskaลบnik moลผna zdefiniowaฤ‡ za pomocฤ… skล‚adni

	var variable_name *type

Gwiazdka (*) oznacza, ลผe โ€‹โ€‹zmienna jest wskaลบnikiem. Wiฤ™cej zrozumiesz wykonujฤ…c poniลผszy 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)}

Dane wyjล›ciowe bฤ™dฤ…

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

Struktury

Struktura to typ danych zdefiniowany przez uลผytkownika, ktรณry sam zawiera jeszcze jeden element tego samego lub innego typu.

Korzystanie ze struktury jest procesem dwuetapowym.

Najpierw utwรณrz (zadeklaruj) typ struktury

Po drugie, utwรณrz zmienne tego typu do przechowywania wartoล›ci.

Struktury sฤ… uลผywane gล‚รณwnie wtedy, gdy chcesz razem przechowywaฤ‡ powiฤ…zane dane.

Weลบ pod uwagฤ™ informacjฤ™ o pracowniku, ktรณra zawiera imiฤ™ i nazwisko, wiek i adres. Moลผna sobie z tym poradziฤ‡ na 2 sposoby

Utwรณrz 3 tablice โ€“ jedna tablica przechowuje nazwiska pracownikรณw, jedna wiek, a trzecia wiek.

Zadeklaruj typ struktury za pomocฤ… 3 pรณl โ€“ nazwy, adresu i wieku. Utwรณrz tablicฤ™ tego typu struktury, w ktรณrej kaลผdy element jest obiektem struktury majฤ…cym nazwฤ™, adres i wiek.

Pierwsze podejล›cie nie jest skuteczne. W tego rodzaju scenariuszach struktury sฤ… wygodniejsze.

Skล‚adnia deklarowania struktury jest nastฤ™pujฤ…ca

type structname struct {
   variable_1 variable_1_type
   variable_2 variable_2_type
   variable_n variable_n_type
}

Przykล‚adem deklaracji struktury jest

type emp struct {
    name string
    address string
    age int
}

Tutaj tworzony jest nowy typ zdefiniowany przez uลผytkownika o nazwie emp. Teraz moลผesz tworzyฤ‡ zmienne typu emp, uลผywajฤ…c skล‚adni

	var variable_name struct_name

Przykล‚adem jest

var empdata1 emp 

Moลผesz ustawiฤ‡ wartoล›ci dla empdata1 jako

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

Moลผna takลผe utworzyฤ‡ zmiennฤ… struktury i przypisaฤ‡ wartoล›ci wedล‚ug

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

Tutaj trzeba zachowaฤ‡ kolejnoล›ฤ‡ elementรณw. Raj zostanie przypisany do imienia, nastฤ™pnego elementu do adresowania i ostatniego do wieku.

Wykonaj poniลผszy kod

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

Wydajnoล›ฤ‡

John
Raj

Metody (nie funkcje)

Metoda to funkcja posiadajฤ…ca argument odbiorcy. Archiz technicznego punktu widzenia znajduje siฤ™ pomiฤ™dzy sล‚owem kluczowym func a nazwฤ… metody. Skล‚adnia metody jest taka

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

Przekonwertujmy powyลผszy przykล‚adowy program tak, aby zamiast funkcji uลผywaล‚ metod.

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 nie jest jฤ™zykiem obiektowym i nie ma w nim koncepcji klasy. Metody dajฤ… wyobraลผenie o tym, co robisz w programach obiektowych, w ktรณrych funkcje klasy sฤ… wywoล‚ywane przy uลผyciu skล‚adni nazwaobiektu.nazwafunkcji()

Konkurencja

Go obsล‚uguje wspรณล‚bieลผne wykonywanie zadaล„. Oznacza to, ลผe Go moลผe wykonywaฤ‡ wiele zadaล„ jednoczeล›nie. Rรณลผni siฤ™ to od koncepcji paralelizmu. W paralelizmie zadanie jest dzielone na maล‚e podzadania i wykonywane rรณwnolegle. Natomiast w przypadku wspรณล‚bieลผnoล›ci wiele zadaล„ jest wykonywanych jednoczeล›nie. Wspรณล‚bieลผnoล›ฤ‡ jest osiฤ…gana w Go za pomocฤ… Goroutines i Channels.

Gorutyny

Goroutine to funkcja, ktรณra moลผe dziaล‚aฤ‡ jednoczeล›nie z innymi funkcjami. Zwykle po wywoล‚aniu funkcji sterowanie zostaje przeniesione do wywoล‚ywanej funkcji, a po zakoล„czeniu jej wykonywania kontrola powraca do funkcji wywoล‚ujฤ…cej. Nastฤ™pnie funkcja wywoล‚ujฤ…ca kontynuuje wykonywanie. Funkcja wywoล‚ujฤ…ca czeka, aลผ wywoล‚ana funkcja zakoล„czy wykonywanie, zanim przejdzie do pozostaล‚ych instrukcji.

Jednak w przypadku goroutine funkcja wywoล‚ujฤ…ca nie bฤ™dzie czekaฤ‡ na zakoล„czenie wykonywania wywoล‚anej funkcji. Bฤ™dzie kontynuowaฤ‡ wykonywanie z nastฤ™pnymi instrukcjami. W programie moลผesz mieฤ‡ wiele goroutines.

Ponadto gล‚รณwny program zakoล„czy dziaล‚anie po zakoล„czeniu wykonywania swoich instrukcji i nie bฤ™dzie czekaฤ‡ na zakoล„czenie wywoล‚anych procedur gor.

Goroutine jest wywoล‚ywany za pomocฤ… sล‚owa kluczowego go, po ktรณrym nastฤ™puje wywoล‚anie funkcji.

Przykล‚ad

go add(x,y)

Gorutyny zrozumiesz dziฤ™ki poniลผszym przykล‚adom Golang. Wykonaj poniลผszy 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")
	}
}

Dane wyjล›ciowe bฤ™dฤ…

In main
In main
In main
In main
In main

Tutaj gล‚รณwny program zakoล„czyล‚ wykonywanie jeszcze przed rozpoczฤ™ciem goroutine. Display() to goroutine wywoล‚ywana przy uลผyciu skล‚adni

go function_name(parameter list)

W powyลผszym kodzie funkcja main() nie czeka na zakoล„czenie funkcji display(), a funkcja main() zakoล„czyล‚a wykonywanie, zanim funkcja display() wykonaล‚a swรณj kod. Zatem instrukcja print wewnฤ…trz display() nie zostaล‚a wydrukowana.

Teraz modyfikujemy program, aby drukowaล‚ takลผe instrukcje z display(). Dodajemy opรณลบnienie czasowe wynoszฤ…ce 2 sekundy w pฤ™tli for funkcji main() i 1 sekundฤ™ opรณลบnienia w pฤ™tli for funkcji 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")
	}
}

Dane wyjล›ciowe bฤ™dฤ… nieco podobne do

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

Tutaj moลผesz zobaczyฤ‡, ลผe obie pฤ™tle sฤ… wykonywane w sposรณb nakล‚adajฤ…cy siฤ™ ze wzglฤ™du na wspรณล‚bieลผne wykonanie.

Kanaล‚y

Kanaล‚y umoลผliwiajฤ… funkcjom komunikacjฤ™ miฤ™dzy sobฤ…. Moลผna go traktowaฤ‡ jako medium, w ktรณrym jedna procedura umieszcza dane i uzyskuje do niej dostฤ™p inna procedura na serwerze Golang.

Kanaล‚ moลผna zadeklarowaฤ‡ za pomocฤ… skล‚adni

channel_variable := make(chan datatype)

Przykล‚ad:

	ch := make(chan int)

Dane do kanaล‚u moลผna wysyล‚aฤ‡ za pomocฤ… skล‚adni

channel_variable <- variable_name

Przykล‚ad

    ch <- x

Dane z kanaล‚u moลผna odbieraฤ‡ za pomocฤ… skล‚adni

    variable_name := <- channel_variable

Przykล‚ad

   y := <- ch

W powyลผszych przykล‚adach goroutine w jฤ™zyku Go widziaล‚eล›, ลผe gล‚รณwny program nie czeka na goroutine. Ale tak nie jest, gdy w grฤ™ wchodzฤ… kanaล‚y. Zaล‚รณลผmy, ลผe jeล›li goroutine przesyล‚a dane do kanaล‚u, funkcja main() bฤ™dzie czekaฤ‡ na instrukcjฤ™ odbierajฤ…cฤ… dane kanaล‚u, aลผ otrzyma dane.

Zobaczysz to w poniลผszych przykล‚adach jฤ™zykรณw Go. Najpierw napisz normalnฤ… goroutine i zobacz zachowanie. Nastฤ™pnie zmodyfikuj program, aby korzystaล‚ z kanaล‚รณw i zobacz zachowanie.

Wykonaj poniลผszy 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()")
}

Dane wyjล›ciowe bฤ™dฤ…

Inside main()

Funkcja main() zakoล„czyล‚a wykonywanie i zakoล„czyล‚a dziaล‚anie przed wykonaniem goroutine. Zatem wydruk wewnฤ…trz display() nie zostaล‚ wykonany.

Teraz zmodyfikuj powyลผszy program, aby korzystaฤ‡ z kanaล‚รณw i zobaczyฤ‡ zachowanie.

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

Dane wyjล›ciowe bฤ™dฤ…

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

Tutaj dzieje siฤ™ funkcja main() po osiฤ…gniฤ™ciu x := <-ch bฤ™dzie czekaฤ‡ na dane na kanale ch. Funkcja display() czeka 5 sekund, a nastฤ™pnie przesyล‚a dane do kanaล‚u ch. Funkcja main() po odebraniu danych z kanaล‚u zostaje odblokowana i kontynuuje wykonywanie.

Nadawca przesyล‚ajฤ…cy dane do kanaล‚u moลผe poinformowaฤ‡ odbiorcรณw, ลผe zamykajฤ…c kanaล‚, nie bฤ™dฤ… juลผ dodawane ลผadne dane do kanaล‚u. Jest to uลผywane gล‚รณwnie wtedy, gdy uลผywasz pฤ™tli do przesyล‚ania danych do kanaล‚u. Kanaล‚ moลผna zamknฤ…ฤ‡ za pomocฤ…

close(channel_name)

Natomiast po stronie odbiornika moลผna sprawdziฤ‡ czy kanaล‚ jest zamkniฤ™ty za pomocฤ… dodatkowej zmiennej podczas pobierania danych z kanaล‚u za pomocฤ…

variable_name, status := <- channel_variable

Jeล›li status ma wartoล›ฤ‡ True oznacza to, ลผe otrzymaล‚eล› dane z kanaล‚u. Jeล›li faล‚szywe, oznacza to, ลผe prรณbujesz czytaฤ‡ z zamkniฤ™tego kanaล‚u

Moลผesz takลผe uลผywaฤ‡ kanaล‚รณw do komunikacji pomiฤ™dzy goroutinami. Naleลผy uลผyฤ‡ 2 goroutines โ€“ jedna wypycha dane do kanaล‚u, a druga odbiera dane z kanaล‚u. Zobacz poniลผszy 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()")
}

Tutaj sฤ… 2 podprogramy, jeden wpycha dane do kanaล‚u, a drugi drukuje dane do kanaล‚u. Funkcja add_to_channel dodaje liczby od 0 do 9 i zamyka kanaล‚. Jednoczeล›nie funkcja fetch_from_channel czeka na

x, flag := <- ch i gdy dane stanฤ… siฤ™ dostฤ™pne, drukuje je. Wychodzi, gdy flaga jest faล‚szywa, co oznacza, ลผe โ€‹โ€‹kanaล‚ jest zamkniฤ™ty.

Oczekiwanie w funkcji main() ma na celu uniemoลผliwienie wyjล›cia z funkcji main() do czasu, aลผ goroutines zakoล„czฤ… wykonywanie.

Wykonaj kod i zobacz wynik jako

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

Wybierz

Select moลผna postrzegaฤ‡ jako instrukcjฤ™ switch, ktรณra dziaล‚a na kanaล‚ach. Tutaj instrukcje case bฤ™dฤ… operacjฤ… kanaล‚u. Zazwyczaj kaลผda instrukcja case bฤ™dzie prรณbฤ… odczytu z kanaล‚u. Gdy ktรณrykolwiek z przypadkรณw jest gotowy (kanaล‚ jest odczytywany), wykonywana jest instrukcja powiฤ…zana z tym przypadkiem. Jeล›li wiele przypadkรณw jest gotowych, zostanie wybrany losowy przypadek. Moลผesz mieฤ‡ domyล›lny przypadek, ktรณry jest wykonywany, jeล›li ลผaden z przypadkรณw nie jest gotowy.

Zobaczmy poniลผszy 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)
    }
}

Wykonanie powyลผszego programu da wynik:

from data2()

Tutaj instrukcja select czeka, aลผ dane bฤ™dฤ… dostฤ™pne w ktรณrymkolwiek z kanaล‚รณw. Funkcja data2() dodaje dane do kanaล‚u po 2 sekundowym uล›pieniu, co spowoduje wykonanie drugiego przypadku.

Dodaj domyล›lny przypadek do zaznaczenia w tym samym programie i zobacz wynik. Tutaj, po osiฤ…gniฤ™ciu bloku wyboru, jeล›li ลผaden przypadek nie ma gotowych danych na kanale, wykona domyล›lny blok bez czekania, aลผ dane bฤ™dฤ… dostฤ™pne na ktรณrymkolwiek kanale.

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

Ten program da wynik:

Default case executed			

Dzieje siฤ™ tak dlatego, ลผe po osiฤ…gniฤ™ciu bloku wyboru ลผaden kanaล‚ nie miaล‚ danych do odczytu. Zatem wykonywany jest przypadek domyล›lny.

Mutex

Mutex to skrรณt od mutual exclusion (wzajemnego wykluczania). Mutex jest uลผywany, gdy nie chcesz, aby zasรณb byล‚ dostฤ™pny dla wielu podprogramรณw jednoczeล›nie. Mutex ma 2 metody โ€“ Lock i Unlock. Mutex jest zawarty w pakiecie sync. Musisz wiฤ™c zaimportowaฤ‡ pakiet sync. Instrukcje, ktรณre muszฤ… byฤ‡ wykonywane wzajemnie wykluczajฤ…co, mogฤ… byฤ‡ umieszczone wewnฤ…trz mutex.Lock() i mutex.Unlock().

Nauczmy siฤ™ muteksu na przykล‚adzie liczenia liczby wykonaล„ pฤ™tli. W tym programie oczekujemy, ลผe procedura wykona pฤ™tlฤ™ 10 razy, a licznik zostanie zapisany w postaci sumy. Wywoล‚ujesz tฤ™ procedurฤ™ 3 razy, wiฤ™c ล‚ฤ…czna liczba powinna wynosiฤ‡ 30. Liczba jest przechowywana w zmiennej globalnej count.

Najpierw uruchamiasz program bez mutexu

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

Zobacz wynik

 Count after i=1 Count: 11
Count after i=3 Count: 12
Count after i=2 Count: 13
Final Count: 13

Wynik moลผe byฤ‡ inny, gdy go wykonasz, ale wynik koล„cowy nie bฤ™dzie wynosiล‚ 30.

Tutaj dzieje siฤ™ tak, ลผe 3 goroutines prรณbujฤ… zwiฤ™kszyฤ‡ liczbฤ™ pฤ™tli przechowywanฤ… w zmiennej count. Zaล‚รณลผmy, ลผe w danej chwili liczba wynosi 5, a goroutine1 zwiฤ™kszy liczbฤ™ do 6. Gล‚รณwne kroki obejmujฤ…

Skopiuj licznik do temp

Zwiฤ™ksz temp

Temp. przechowywania z powrotem do zliczenia

Zaล‚รณลผmy, ลผe wkrรณtce po wykonaniu kroku 3 przez goroutine1; inna goroutine moลผe mieฤ‡ starฤ… wartoล›ฤ‡, powiedzmy 3 wykonuje powyลผsze kroki i zapisuje 4 z powrotem, co jest bล‚ฤ™dne. Moลผna temu zapobiec, uลผywajฤ…c muteksu, ktรณry powoduje, ลผe inne procedury czekajฤ…, gdy jedna z nich juลผ uลผywa zmiennej.

Teraz uruchomisz program z mutexem. Tutaj wyลผej wymienione 3 kroki sฤ… wykonywane w muteksie.

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

Teraz bฤ™dzie wynik

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

Tutaj otrzymujemy oczekiwany wynik jako wynik koล„cowy. Poniewaลผ instrukcje odczytywania, zwiฤ™kszania i zapisywania liczby licznika sฤ… wykonywane w muteksie.

Obsล‚uga bล‚ฤ™dรณw

Bล‚ฤ™dy to nietypowe warunki, takie jak zamkniฤ™cie nieotwartego pliku, otwarcie pliku, ktรณry nie istnieje itp. Funkcje zwykle zwracajฤ… bล‚ฤ™dy jako ostatniฤ… zwracanฤ… wartoล›ฤ‡.

Poniลผszy przykล‚ad wyjaล›nia wiฤ™cej na temat bล‚ฤ™du.

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

Wyjล›cie bฤ™dzie:

open /invalid.txt: no such file or directory

Tutaj prรณbowaliล›my otworzyฤ‡ nieistniejฤ…cy plik, ale zwrรณciล‚ on bล‚ฤ…d do zmiennej er. Jeล›li plik jest prawidล‚owy, bล‚ฤ…d bฤ™dzie miaล‚ wartoล›ฤ‡ null

Niestandardowe bล‚ฤ™dy

Korzystajฤ…c z tej funkcji, moลผesz tworzyฤ‡ niestandardowe bล‚ฤ™dy. Odbywa siฤ™ to za pomocฤ… New() pakietu bล‚ฤ™dรณw. Przepiszemy powyลผszy program, aby wykorzystaฤ‡ niestandardowe bล‚ฤ™dy.

Uruchom poniลผszy 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)
    }  
}

Wyjล›cie bฤ™dzie:

Custom error message:File name is wrong

Tutaj area() zwraca pole kwadratu. Jeล›li wartoล›ฤ‡ wejล›ciowa jest mniejsza niลผ 1, funkcja area() zwraca komunikat o bล‚ฤ™dzie.

Czytanie plikรณw

Pliki sล‚uลผฤ… do przechowywania danych. Go pozwala nam na odczytanie danych z plikรณw

Najpierw utwรณrz plik data.txt w swoim obecnym katalogu z poniลผszฤ… zawartoล›ciฤ….

Line one
Line two
Line three

Teraz uruchom poniลผszy program, aby zobaczyฤ‡, ลผe drukuje zawartoล›ฤ‡ caล‚ego pliku jako dane wyjล›ciowe

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

Tutaj dane, err := ioutil.ReadFile(โ€œdata.txtโ€) odczytuje dane i zwraca sekwencjฤ™ bajtรณw. Podczas drukowania jest konwertowany do formatu ciฤ…gu znakรณw.

Zapisywanie plikรณw

Zobaczysz to za pomocฤ… programu

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

Tutaj tworzony jest plik test.txt. Jeล›li plik juลผ istnieje, zawartoล›ฤ‡ pliku zostanie obciฤ™ta. Funkcja Writeline() sล‚uลผy do zapisywania zawartoล›ci pliku. Nastฤ™pnie zamknฤ…ล‚eล› plik za pomocฤ… Close().

ลšciฤ…gawka

W tym samouczku Go omรณwiliล›my:

Temat OPIS Skล‚adnia
Typy podstawowe Numeryczne, ล‚aล„cuchowe, bool
Zmienne Deklaruj i przypisuj wartoล›ci do zmiennych var nazwa_zmiennej typ
var nazwa_zmiennej typ = wartoล›ฤ‡
var nazwa_zmiennej1, nazwa_zmiennej2 = wartoล›ฤ‡1, wartoล›ฤ‡2
nazwa_zmiennej := wartoล›ฤ‡
Staล‚e Zmienne, ktรณrych wartoล›ci nie moลผna zmieniฤ‡ po przypisaniu zmienna staล‚a = wartoล›ฤ‡
Dla pฤ™tli Wykonuj instrukcje w pฤ™tli. dla wyraลผenia_inicjalizacyjnego; wyraลผenie_oceny; iteracja_wyraลผenie{
// jedno lub wiฤ™cej instrukcji
}
Jeล›li inaczej Jest to stwierdzenie warunkowe jeล›li warunek{
// oล›wiadczenia_1
Else {}
// oล›wiadczenia_2
}
wyล‚ฤ…cznik Instrukcja warunkowa z wieloma przypadkami wyraลผenie przeล‚ฤ…czajฤ…ce {
wartoล›ฤ‡ przypadku_1:
oล›wiadczenia_1
wartoล›ฤ‡ przypadku_2:
oล›wiadczenia_2
wartoล›ฤ‡ przypadku_n:
oล›wiadczenia_n
domyล›lna:
oล›wiadczenia_domyล›lne
}
Szyk Staล‚y rozmiar nazwanej sekwencji elementรณw tego samego typu nazwa tablicy := [rozmiar] typ {wartoล›ฤ‡_0, wartoล›ฤ‡_1,โ€ฆ, wartoล›ฤ‡_rozmiar-1}
Plaster Czฤ™ล›ฤ‡ lub segment tablicy var nazwa_plasterku [] type = nazwa_tablicy[poczฤ…tek:koniec]
Funkcje Blok instrukcji realizujฤ…cy okreล›lone zadanie func nazwa_funkcji(typ parametru_1, typ parametru_n) typ_zwrotu {
//sprawozdania
}
Pakiety Sล‚uลผฤ… do organizowania kodu. Zwiฤ™ksza czytelnoล›ฤ‡ kodu i moลผliwoล›ฤ‡ jego ponownego uลผycia importuj nazwฤ™_pakietu
Odraczaฤ‡ Opรณลบnia wykonanie funkcji do momentu zakoล„czenia wykonywania funkcji zawierajฤ…cej odroczenie nazwa_funkcji(lista_parametrรณw)
wskaลบniki Przechowuje adres pamiฤ™ci innej zmiennej. var nazwa_zmiennej *typ
Structure Typ danych zdefiniowany przez uลผytkownika, ktรณry sam zawiera jeszcze jeden element tego samego lub innego typu wpisz nazwa struktury struktura {
zmienna_1 zmienna_1_typ
zmienna_2 zmienna_2_typ
zmienna_n zmienna_n_typ
}
Metody Metoda to funkcja posiadajฤ…ca argument odbiorcy func (typ zmiennej) nazwa_metody(lista_parametrรณw) {
}
Gorutyna Funkcja, ktรณra moลผe dziaล‚aฤ‡ jednoczeล›nie z innymi funkcjami. przejdลบ nazwa_funkcji (lista_parametrรณw)
Kanaล‚ Sposรณb komunikowania siฤ™ funkcji miฤ™dzy sobฤ…. Medium, w ktรณrym jedna procedura umieszcza dane i do ktรณrego uzyskuje dostฤ™p inna procedura. Ogล‚osiฤ‡:
ch := make(chan int)
Wyล›lij dane do kanaล‚u:
zmienna_kanaล‚u <- nazwa_zmiennej
Odbierz z kanaล‚u:
nazwa_zmiennej := <- zmienna_kanaล‚u
Wybierz Instrukcja Switch, ktรณra dziaล‚a na kanaล‚ach. Instrukcje case bฤ™dฤ… operacjฤ… kanaล‚u. Gdy ktรณrykolwiek kanaล‚ jest gotowy z danymi, wykonywana jest instrukcja powiฤ…zana z tym case wybieraฤ‡ {
przypadek x := <-chan1:
fmt.Drukuj(x)
przypadek y := <-chan2:
fmt.Println(y)
}
Mutex Mutex jest uลผywany, gdy nie chcesz, aby wiele podprogramรณw miaล‚o dostฤ™p do zasobu jednoczeล›nie. Mutex ma 2 metody โ€“ Zablokuj i Odblokuj mutex.Lock()
//sprawozdania
mutex.Odblokuj().
Czytaj pliki Odczytuje dane i zwraca sekwencjฤ™ bajtรณw. Dane, bล‚ฤ…d:= ioutil.ReadFile(nazwa pliku)
Zapisz plik Zapisuje dane do pliku l, bล‚ฤ…d := f.WriteString(text_to_write)

Podsumuj ten post nastฤ™pujฤ…co: