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