Výukový program Golangu
Co je Go?
Go (také známý jako Golang) je programovací jazyk s otevřeným zdrojovým kódem vyvinutý společností Google. Je to staticky typovaný kompilovaný jazyk. Go podporuje souběžné programování, tj. umožňuje spouštět více procesů současně. Toho je dosaženo pomocí kanálů, goroutin atd. Go Language má garbage collection, který sám provádí správu paměti a umožňuje odložené provádění funkcí.
V tomto výukovém programu Learn Go Language se naučíme všechny základy golangu.
Jak stáhnout a nainstalovat GO
Krok 1) Přejít https://golang.org/dl/. Stáhněte si binární soubor pro váš OS.
Krok 2) Double klikněte na instalační program a klikněte na Spustit.
Krok 3) Klepněte na tlačítko Další
Krok 4) Vyberte instalační složku a klikněte na Další.

Krok 5) Po dokončení instalace klikněte na Dokončit.

Krok 6) Jakmile je instalace dokončena, můžete ji ověřit otevřením terminálu a zadáním
go version
Tím se zobrazí nainstalovaná verze go

Váš program First Go – Go Hello World!
Vytvořte složku s názvem studyGo. V tomto kurzu jazyka Go vytvoříme naše programy go uvnitř této složky. Go soubory jsou vytvořeny s příponou .jít. Programy Go můžete spouštět pomocí syntaxe
go run <filename>
Vytvořte soubor s názvem first.go a přidejte do něj níže uvedený kód a uložte
package main
import ("fmt")
func main() {
fmt.Println("Hello World! This is my first Go program\n")
}

Přejděte do této složky ve svém terminálu. Spusťte program pomocí příkazu
běž první běžet
Můžete vidět výstupní tisk
Hello World! This is my first Go program

Nyní pojďme diskutovat o výše uvedeném programu.
package main – Každý program Go Language by měl začínat názvem balíčku. Go nám umožňuje používat balíčky v jiných go programech, a proto podporuje opětovné použití kódu. Spuštění programu Go začíná kódem uvnitř balíčku s názvem main.
import fmt – importuje balíček fmt. Tento balíček implementuje I/O funkce.
func main() – Toto je funkce, od které začíná provádění programu. Hlavní funkce by měla být vždy umístěna v hlavním balíčku. Pod main() můžete napsat kód dovnitř { }.
fmt.Println – Toto vytiskne text na obrazovku pomocí funkce Println funkce fmt.
Poznámka: Když v níže uvedených částech tohoto tutoriálu Go zmíníte spustit/spustit kód, znamená to uložit kód do souboru s příponou .go a spustit jej pomocí syntaxe
go run <filename>
Typy dat
Typy (datové typy) představují typ hodnoty uložené v proměnné, typ hodnoty, kterou funkce vrací atd.
V jazyce Go existují tři základní typy
Číselné typy – Představují číselné hodnoty, které zahrnují celé číslo, plovoucí desetinnou čárku a komplexní hodnoty. Různé číselné typy jsou:
int8 – 8bitová celá čísla se znaménkem.
int16 – 16bitová celá čísla se znaménkem.
int32 – 32bitová celá čísla se znaménkem.
int64 – 64bitová celá čísla se znaménkem.
uint8 – 8bitová celá čísla bez znaménka.
uint16 – 16bitová celá čísla bez znaménka.
uint32 – 32bitová celá čísla bez znaménka.
uint64 – 64bitová celá čísla bez znaménka.
float32 – 32bitová čísla s plovoucí desetinnou čárkou.
float64 – 64bitová čísla s plovoucí desetinnou čárkou.
complex64 – má float32 reálné a imaginární části.
complex128 – má float32 reálné a imaginární části.
Typy řetězců – Představuje posloupnost bajtů (znaků). S řetězci můžete provádět různé operace, jako je zřetězení řetězců, extrahování podřetězců atd
Booleovské typy – Představuje 2 hodnoty, buď true nebo false.
Rozhraní Golang
Rozhraní Golang je kolekce signatur metod používaných typem k implementaci chování objektů. Hlavním cílem rozhraní Golang je poskytnout podpisy metod s názvy, argumenty a návratovými typy. Je na typu, aby deklaroval a implementoval metodu. Rozhraní v Golangu lze deklarovat pomocí klíčového slova „rozhraní“.
Proměnné
Proměnné ukazují na paměťové místo, které ukládá nějaký druh hodnoty. Parametr type (v níže uvedené syntaxi) představuje typ hodnoty, kterou lze uložit do paměti.
Proměnnou lze deklarovat pomocí syntaxe
var <variable_name> <type>
Jakmile deklarujete proměnnou typu, můžete proměnnou přiřadit libovolné hodnotě tohoto typu.
Můžete také zadat počáteční hodnotu proměnné během samotné deklarace pomocí
var <variable_name> <type> = <value>
Pokud deklarujete proměnnou s počáteční hodnotou, Go a odvodit typ proměnné z typu přiřazené hodnoty. Takže můžete typ během deklarace vynechat pomocí syntaxe
var <variable_name> = <value>
Můžete také deklarovat více proměnných pomocí syntaxe
var <variable_name1>, <variable_name2> = <value1>, <value2>
Níže uvedený program v tomto tutoriálu Go obsahuje některé příklady Golang deklarací proměnných
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)
}
Výstup bude
x: 3 y: 20 z: 50 i and j: 100 hello
Go Language také poskytuje snadný způsob, jak deklarovat proměnné s hodnotou vynecháním klíčového slova var using
<variable_name> := <value>
Všimněte si, že jste použili := místo =. Nemůžete použít := pouze k přiřazení hodnoty proměnné, která je již deklarována. := se používá k deklaraci a přiřazení hodnoty.
Vytvořte soubor s názvem assign.go s následujícím kódem
package main
import ("fmt")
func main() {
a := 20
fmt.Println(a)
//gives error since a is already declared
a := 30
fmt.Println(a)
}
Proveďte spuštění příkazu assign.go, abyste viděli výsledek jako
./assign.go:7:4: no new variables on left side of :=
Proměnné deklarované bez počáteční hodnoty budou mít 0 pro číselné typy, false pro booleovské a prázdný řetězec pro řetězce
Konstanty
Konstantní proměnné jsou ty proměnné, jejichž hodnotu nelze po přiřazení změnit. Konstanta v programovacím jazyce Go je deklarována pomocí klíčového slova „const“
Vytvořte soubor s názvem konstantní.go a s následujícím kódem
package main
import ("fmt")
func main() {
const b =10
fmt.Println(b)
b = 30
fmt.Println(b)
}
Proveďte go run konstantní.go, abyste viděli výsledek jako
.constant.go:7:4: cannot assign to b
Pro příklady smyčky
Smyčky se používají k opakovanému provádění bloku příkazů na základě podmínky. Většina programovacích jazyků poskytuje 3 typy smyček – for, while, do while. Ale programovací jazyk Go podporuje pouze smyčku.
Syntaxe smyčky Golang for je
for initialisation_expression; evaluation_expression; iteration_expression{
// one or more statement
}
Inicializační_výraz je proveden jako první (a pouze jednou) ve smyčce Golang for.
Poté je vyhodnocen výraz_vyhodnocení a pokud je pravdivý, provede se kód uvnitř bloku.
Provede se id iteration_expression a znovu se vyhodnotí evaluační_výraz. Pokud je to pravda, blok příkazů se provede znovu. To bude pokračovat, dokud se výraz evaluace nestane nepravdivým.
Zkopírujte níže uvedený program do souboru a spusťte jej, abyste viděli čísla pro tisk smyček Golang for od 1 do 5
package main
import "fmt"
func main() {
var i int
for i = 1; i <= 5; i++ {
fmt.Println(i)
}
}
Výstup je
1 2 3 4 5
Pokud jinak
If else je podmíněný příkaz. Synax je
if condition{
// statements_1
}else{
// statements_2
}
Zde se vyhodnotí podmínka a pokud je pravdivá, budou provedeny příkazy_1, jinak budou provedeny příkazy_2.
Můžete použít příkaz if bez jiného také. Můžete také mít zřetězené příkazy if else. Níže uvedené programy vysvětlí více o tom, jestli jinak.
Spusťte níže uvedený program. Zkontroluje, zda je číslo x menší než 10. Pokud ano, vypíše „x je menší než 10“
package main
import "fmt"
func main() {
var x = 50
if x < 10 {
//Executes if x < 10
fmt.Println("x is less than 10")
}
}
Protože hodnota x je větší než 10, příkaz uvnitř bloku if nebude proveden.
Nyní se podívejte na níže uvedený program. V tomto tutoriálu programovacího jazyka Go máme blok else, který se provede při selhání vyhodnocení 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")
}
}
Tento program vám poskytne výstup
x is greater than or equals 10
Nyní v tomto tutoriálu Go uvidíme program s více bloky if else (zřetězenými, pokud jinak). Proveďte níže uvedený příklad Go. Kontroluje, zda je číslo menší než 10 nebo mezi 10-90 nebo větší než 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")
}
}
Zde nejprve podmínka if zkontroluje, zda je x menší než 10 a není. Takže zkontroluje další podmínku (else if), zda je mezi 10 a 90, což je také nepravdivé. Takže pak provede blok v sekci else, která dává výstup
x is greater than 90
Vypínač
Switch je další podmíněný příkaz. Příkazy Switch vyhodnotí výraz a výsledek se porovná se sadou dostupných hodnot (případů). Jakmile je nalezena shoda, jsou provedeny příkazy spojené s touto shodou (případem). Pokud není nalezena žádná shoda, nic se neprovede. Můžete také přidat výchozí případ pro přepnutí, který se provede, pokud nebudou nalezeny žádné jiné shody. Syntaxe přepínače je
switch expression {
case value_1:
statements_1
case value_2:
statements_2
case value_n:
statements_n
default:
statements_default
}
Zde se hodnota výrazu porovnává s hodnotami v každém případě. Jakmile je nalezena shoda, jsou provedeny příkazy spojené s daným případem. Pokud není nalezena žádná shoda, provedou se příkazy ve výchozí sekci.
Spusťte níže uvedený 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")
}
}
Získáte výstup jako
Sum is 3
Změňte hodnotu a a b na 3 a výsledek bude
Printing default
Můžete také mít více hodnot v případě, když je oddělíte čárkou.
Pole
Pole představuje pevnou velikost, pojmenovanou sekvenci prvků stejného typu. Nemůžete mít pole, které obsahuje celé číslo i znaky. Jakmile definujete velikost, nemůžete změnit velikost pole.
Syntaxe pro deklaraci pole je
var arrayname [size] type
Každému prvku pole lze přiřadit hodnotu pomocí syntaxe
arrayname [index] = value
Index pole začíná od 0 až velikost-1.
Hodnoty prvkům pole můžete přiřadit během deklarace pomocí syntaxe
arrayname := [size] type {value_0,value_1,…,value_size-1}
Parametr size můžete také ignorovat při deklarování pole s hodnotami nahrazením size za ... a překladač zjistí délku z počtu hodnot. Syntaxe je
arrayname := […] type {value_0,value_1,…,value_size-1}
Délku pole můžete zjistit pomocí syntaxe
len(arrayname)
Chcete-li porozumět poli, spusťte níže uvedený příklad Go
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])
}
Výstup
Two 3 [One Two Three] [1 2 3 4 5] 5
Funkce Golang Slice and Append
Řez je část nebo segment pole. Nebo je to pohled nebo částečný pohled na základní pole, na které ukazuje. K prvkům řezu můžete přistupovat pomocí názvu řezu a čísla indexu stejně jako v poli. Nemůžete změnit délku pole, ale můžete změnit velikost řezu.
Obsah řezu jsou ve skutečnosti ukazatele na prvky pole. To znamená pokud změníte jakýkoli prvek v řezu, bude ovlivněn i obsah základního pole.
Syntaxe pro vytvoření řezu je
var slice_name [] type = array_name[start:end]
Tím se vytvoří řez s názvem název_řezu z pole s názvem název_pole s prvky na začátku indexu až na konci-1.
Nyní v tomto tutoriálu Golang spustíme níže uvedený program. Program z pole vytvoří řez a vytiskne jej. Také můžete vidět, že úprava obsahu v řezu změní skutečné pole.
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)
}
Tím se vytiskne výsledek 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]
Existují určité funkce jako Golang len, Golang append, které můžete použít na řezy
len(název_slice) – vrátí délku řezu
připojit(název_dílce, hodnota_1, hodnota_2) – Golang append se používá k připojení value_1 a value_2 k existujícímu řezu.
append(nale_slice1,nazev_slice2…) – připojí název_dílu2 k názvu_dílu1
Spusťte následující 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)
}
Výstup bude
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 nejprve vytvoří 2 řezy a vytiskne jejich délku. Poté připojil jeden plátek k druhému a poté k výslednému plátku připojil řetězec.
Funkce
Funkce představuje blok příkazů, který provádí určitou úlohu. Deklarace funkce nám říká název funkce, návratový typ a vstupní parametry. Definice funkce představuje kód obsažený ve funkci. Syntaxe pro deklaraci funkce je
func function_name(parameter_1 type, parameter_n type) return_type {
//statements
}
Parametry a návratové typy jsou volitelné. Z funkce můžete také vrátit více hodnot.
Nyní v tomto tutoriálu Golang spustíme následující příklad Golang. Zde funkce s názvem calc přijme 2 čísla a provede sčítání a odčítání a vrací obě hodnoty.
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)
}
Výstup bude
Sum 25 Diff 5
Balíčky
Balíčky se používají k uspořádání kódu. Ve velkém projektu není možné napsat kód do jednoho souboru. Programovací jazyk Go nám umožňuje organizovat kód do různých balíčků. To zvyšuje čitelnost kódu a opětovnou použitelnost. Spustitelný program Go by měl obsahovat balíček s názvem main a provádění programu začíná funkcí s názvem main. Pomocí syntaxe můžete importovat další balíčky do našeho programu
import package_name
V tomto tutoriálu Golang uvidíme a probereme, jak vytvářet a používat balíčky v následujícím příkladu Golang.
Krok 1) Vytvořte soubor s názvem package_example.go a přidejte níže uvedený kód
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)
}
Ve výše uvedeném programu fmt je balíček, který nám programovací jazyk Go poskytuje především pro I/O účely. Můžete také vidět balíček s názvem výpočet. Uvnitř main() můžete vidět krokový součet := výpočet.Do_add(x,y). To znamená, že vyvoláváte funkci Do_add z výpočtu balíčku.
Krok 2) Nejprve byste měli vytvořit výpočet balíčku ve složce se stejným názvem ve složce src v go. Instalovanou cestu go lze zjistit z proměnné PATH.
Pro Mac najděte cestu spuštěním echo $PATH

Cesta je tedy /usr/local/go
Pro Windows najděte cestu spuštěním echo %GOROOT%

Zde je cesta C:\Go\
Krok 3) Přejděte do složky src (/usr/local/go/src pro Mac a C:\Go\src pro Windows). Nyní z kódu je název balíčku výpočet. Go vyžaduje, aby byl balíček umístěn ve stejnojmenném adresáři v adresáři src. Vytvořte adresář s názvem výpočet ve složce src.
Krok 4) Vytvořte soubor s názvem calc.go (Můžete zadat libovolný název, ale na názvu balíčku v kódu záleží. Zde by to měl být výpočet) v adresáři výpočtu a přidejte níže uvedený kód
package calculation
func Do_add(num1 int, num2 int)(int) {
sum := num1 + num2
return sum
}
Krok 5) Spusťte příkaz go install z adresáře pro výpočty, který zkompiluje soubor calc.go.

Krok 6) Nyní se vraťte na package_example.go a spusťte go run package_example.go. Výstupem bude součet 25.
Všimněte si, že název funkce Do_add začíná velkým písmenem. Je to proto, že pokud název funkce v Go začíná velkým písmenem, znamená to, že ji ostatní programy mohou vidět (přistupovat), jiné programy k ní nemají přístup. Pokud by název funkce byl do_add , dostali byste chybu
nemůže odkazovat na neexportovaný výpočet názvu.
Odložit a stohování odloží
Příkazy odložit se používají k odložení provedení volání funkce, dokud funkce obsahující příkaz odložení nedokončí provedení.
Pojďme se to naučit na příkladu:
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()")
}
Výstup bude
Inside the main() Inside the sample()
Zde je provedení sample() odloženo, dokud se nedokončí provádění uzavírací funkce (main()).
Stacking odložit používá více příkazů odložení. Předpokládejme, že máte ve funkci více příkazů odložení. Go umístí všechna odložená volání funkcí do zásobníku, a jakmile se vrátí uzavírací funkce, složené funkce se provedou v Pořadí Last In First Out (LIFO). Můžete to vidět na níže uvedeném příkladu.
Spusťte níže uvedený kód
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)
}
Výstup bude
4 3 2 1
Zde se nejprve provede kód uvnitř main() a poté se provedou odložená volání funkcí v opačném pořadí, tj. 4, 3,2,1.
Pointers
Před vysvětlením ukazatelů nejprve probereme operátor '&'. Operátor '&' se používá k získání adresy proměnné. Znamená to, že '&a' vytiskne adresu paměti proměnné a.
V tomto tutoriálu Golang spustíme níže uvedený program pro zobrazení hodnoty proměnné a adresy této proměnné
package main
import "fmt"
func main() {
a := 20
fmt.Println("Address:",&a)
fmt.Println("Value:",a)
}
Výsledkem bude
Address: 0xc000078008 Value: 20
Ukazatelská proměnná ukládá paměťovou adresu jiné proměnné. Ukazatel můžete definovat pomocí syntaxe
var variable_name *type
Hvězdička(*) představuje, že proměnná je ukazatel. Více pochopíte spuštěním níže uvedeného programu
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)}
Výstup bude
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 je uživatelsky definovaný datový typ, který sám o sobě obsahuje ještě jeden prvek stejného nebo odlišného typu.
Použití struktury je proces o 2 krocích.
Nejprve vytvořte (deklarujte) typ struktury
Zadruhé vytvořte proměnné tohoto typu pro ukládání hodnot.
Struktury se používají hlavně, když chcete ukládat související data dohromady.
Zvažte část informace o zaměstnanci, která obsahuje jméno, věk a adresu. Můžete to zvládnout 2 způsoby
Vytvořte 3 pole – jedno pole obsahuje jména zaměstnanců, jedno věk a třetí věk.
Deklarujte typ struktury se 3 poli – jméno, adresa a věk. Vytvořte pole tohoto typu struktury, kde každý prvek je objekt struktury se jménem, adresou a stářím.
První přístup není účinný. V těchto typech scénářů jsou struktury pohodlnější.
Syntaxe pro deklaraci struktury je
type structname struct {
variable_1 variable_1_type
variable_2 variable_2_type
variable_n variable_n_type
}
Příkladem deklarace struktury je
type emp struct {
name string
address string
age int
}
Zde se vytvoří nový uživatelsky definovaný typ s názvem emp. Nyní můžete vytvořit proměnné typu emp pomocí syntaxe
var variable_name struct_name
Příkladem je
var empdata1 emp
Hodnoty pro empdata1 můžete nastavit jako
empdata1.name = "John" empdata1.address = "Street-1, Bangalore" empdata1.age = 30
Můžete také vytvořit proměnnou struktury a přiřadit hodnoty podle
empdata2 := emp{"Raj", "Building-1, Delhi", 25}
Zde musíte zachovat pořadí prvků. Raj bude mapován na jméno, další prvek na adresu a poslední na věk.
Spusťte níže uvedený kód
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)
}
Výstup
John Raj
Metody (ne funkce)
Metoda je funkce s argumentem příjemce. Architechnicky je mezi klíčovým slovem func a názvem metody. Syntaxe metody je
func (variable variabletype) methodName(parameter1 paramether1type) {
}
Pojďme převést výše uvedený příklad programu tak, aby používal metody místo funkce.
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 není objektově orientovaný jazyk a nemá koncept třídy. Metody poskytují pocit toho, co děláte v objektově orientovaných programech, kde jsou funkce třídy vyvolány pomocí syntaxe objectname.functionname()
Konkurence
Go podporuje souběžné provádění úloh. To znamená, že Go může provádět více úkolů současně. Liší se od konceptu paralelismu. V paralelismu je úloha rozdělena na malé dílčí úlohy a jsou prováděny paralelně. Ale souběžně se současně provádí několik úkolů. Souběžnosti je dosaženo v Go pomocí Goroutines a Channels.
Goroutines
Gorutina je funkce, která může běžet souběžně s jinými funkcemi. Obvykle, když je funkce vyvolána, ovládací prvek se přenese do volané funkce a jakmile je dokončeno řízení provádění, vrátí se do volající funkce. Volající funkce pak pokračuje ve svém provádění. Volající funkce čeká, až vyvolaná funkce dokončí provádění, než bude pokračovat se zbytkem příkazů.
Ale v případě goroutine nebude volající funkce čekat na dokončení spuštěné funkce. Bude pokračovat v provádění s dalšími příkazy. V programu můžete mít více goroutin.
Také se hlavní program ukončí, jakmile dokončí provádění svých příkazů, a nebude čekat na dokončení vyvolaných goroutin.
Goroutine se vyvolá pomocí klíčového slova go následovaného voláním funkce.
Příklad
go add(x,y)
Golangům níže porozumíte golangovým příkladům. Spusťte níže uvedený 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")
}
}
Výstup bude
In main In main In main In main In main
Zde hlavní program dokončil provádění ještě před zahájením goroutiny. Display() je rutina, která se vyvolává pomocí syntaxe
go function_name(parameter list)
Ve výše uvedeném kódu main() nečeká na dokončení display() a main() dokončilo své provedení dříve, než display() provedlo svůj kód. Takže příkaz k tisku uvnitř display() se nevytiskl.
Nyní upravíme program tak, aby tiskl i výpisy z display(). Přidáme časové zpoždění 2 sekundy ve smyčce for funkce main() a zpoždění 1 sekundy ve smyčce for 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")
}
}
Výstup bude poněkud podobný
In display In main In display In display In main In display In display In main In main In main
Zde můžete vidět, že se obě smyčky provádějí překrývajícím se způsobem kvůli souběžnému provádění.
Kanály
Kanály představují způsob, jak funkce vzájemně komunikovat. Lze jej považovat za médium, kam jedna rutina umísťuje data a je přístupná jinou rutinou na serveru Golang.
Kanál lze deklarovat pomocí syntaxe
channel_variable := make(chan datatype)
Příklad:
ch := make(chan int)
Data můžete odesílat do kanálu pomocí syntaxe
channel_variable <- variable_name
Příklad
ch <- x
Data z kanálu můžete přijímat pomocí syntaxe
variable_name := <- channel_variable
Příklad
y := <- ch
Ve výše uvedených příkladech goroutinu v jazyce Go jste viděli, že hlavní program na goroutinu nečeká. To však není případ, kdy se jedná o kanály. Předpokládejme, že pokud gorrutina posílá data do kanálu, main() počká na příkaz přijímající data kanálu, dokud data nezíská.
Uvidíte to v níže uvedených příkladech jazyka Go. Nejprve napište normální rutinu a podívejte se na chování. Poté upravte program tak, aby používal kanály a sledujte chování.
Spusťte níže uvedený 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()")
}
Výstup bude
Inside main()
Main() dokončilo provádění a skončilo dříve, než se spustí goroutine. Takže tisk uvnitř display() nebyl proveden.
Nyní upravte výše uvedený program tak, aby používal kanály a sledujte chování.
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)
}
Výstup bude
Inside display() Inside main() Printing x in main() after taking from channel: 1234
Zde se stane, že main() při dosažení x := <-ch bude čekat na data na kanálu ch. Display() čeká 5 sekund a poté odešle data do kanálu ch. Main() při příjmu dat z kanálu se odblokuje a pokračuje ve svém provádění.
Odesílatel, který posílá data do kanálu, může informovat příjemce, že do kanálu nebudou přidána žádná další data uzavřením kanálu. To se používá hlavně, když používáte smyčku k přenosu dat do kanálu. Kanál lze uzavřít pomocí
close(channel_name)
A na konci přijímače je možné zkontrolovat, zda je kanál uzavřen pomocí další proměnné při načítání dat z kanálu pomocí
variable_name, status := <- channel_variable
Pokud je stav True, znamená to, že jste přijali data z kanálu. Pokud je false, znamená to, že se pokoušíte číst z uzavřeného kanálu
Můžete také použít kanály pro komunikaci mezi goroutiny. Je třeba použít 2 goroutiny – jeden posílá data do kanálu a druhý přijímá data z kanálu. Viz níže uvedený 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()")
}
Zde jsou 2 podprogramy, jeden posílá data do kanálu a druhý tiskne data do kanálu. Funkce add_to_channel přidá čísla od 0 do 9 a zavře kanál. Současně funkce fetch_from_channel čeká na
x, příznak := <- ch a jakmile budou data dostupná, data vytiskne. Ukončí se, jakmile je příznak nepravdivý, což znamená, že kanál je uzavřen.
Čekání v main() je dáno, aby se zabránilo ukončení main(), dokud goroutiny nedokončí provádění.
Spusťte kód a podívejte se na výstup jako
Read data Send data 0 1 2 3 4 5 6 7 8 9 Empty channel Inside main()
vybrat
Select lze zobrazit jako příkaz switch, který funguje na kanálech. Zde budou případová prohlášení operací kanálu. Obvykle se každý případový příkaz pokusí přečíst z kanálu. Když je některý z případů připraven (kanál je přečten), provede se příkaz spojený s tímto případem. Pokud je připraveno více případů, vybere náhodný. Můžete mít výchozí případ, který se provede, pokud není připraven žádný z případů.
Podívejme se na níže uvedený kód
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)
}
}
Spuštěním výše uvedeného programu získáte výstup:
from data2()
Zde příkaz select čeká, až budou data dostupná v některém z kanálů. Data2() přidá data do kanálu po 2 sekundách spánku, což způsobí provedení druhého případu.
Přidejte výchozí případ k výběru ve stejném programu a podívejte se na výstup. Zde, po dosažení vybraného bloku, pokud žádný případ nemá připravena data na kanálu, provede výchozí blok bez čekání, až budou data dostupná na jakémkoli kanálu.
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")
}
}
Tento program poskytne výstup:
Default case executed
Je to proto, že když byl dosažen blok výběru, žádný kanál neměl data pro čtení. Takže se provede výchozí případ.
Mutex
Mutex je zkratka pro vzájemné vyloučení. Mutex se používá, když nechcete povolit přístup k prostředku více podprogramům současně. Mutex má 2 způsoby – zamknout a odemknout. Mutex je obsažen v synchronizačním balíčku. Musíte tedy importovat synchronizační balíček. Příkazy, které musí být vzájemně výhradně provedeny, mohou být umístěny uvnitř mutex.Lock() a mutex.Unlock().
Pojďme se naučit mutex s příkladem, který počítá, kolikrát je smyčka vykonána. V tomto programu očekáváme, že rutina spustí smyčku 10krát a počet je uložen v součtu. Tuto rutinu voláte 3krát, takže celkový počet by měl být 30. Počet je uložen v globální proměnné count.
Nejprve spustíte 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)
}
Podívejte se na výsledek
Count after i=1 Count: 11 Count after i=3 Count: 12 Count after i=2 Count: 13 Final Count: 13
Výsledek se může při spuštění lišit, ale konečný výsledek nebude 30.
Zde se stane, že se 3 goroutiny pokoušejí zvýšit počet smyček uložený v proměnné count. Předpokládejme, že v okamžiku je počet 5 a goroutine1 zvýší počet na 6. Mezi hlavní kroky patří
Kopírovat počet do temp
Zvýšení teploty
Uložte teplotu zpět k počítání
Předpokládejme, že brzy po provedení kroku 3 goroutine1; jiná goroutine může mít starou hodnotu, řekněme, že 3 provede výše uvedené kroky a uloží 4 zpět, což je špatně. Tomu lze zabránit použitím mutexu, který způsobí, že ostatní rutiny čekají, když jedna rutina již proměnnou používá.
Nyní spustíte program s mutexem. Zde jsou výše uvedené 3 kroky provedeny v mutexu.
package main
import "fmt"
import "time"
import "sync"
import "strconv"
import "math/rand"
//declare a mutex instance
var mu sync.Mutex
//declare count variable, which is accessed by all the routine instances
var count = 0
//copies count to temp, do some processing(increment) and store back to count
//random delay is added between reading and writing of count variable
func process(n int) {
//loop incrementing the count by 10
for i := 0; i < 10; i++ {
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
//lock starts here
mu.Lock()
temp := count
temp++
time.Sleep(time.Duration(rand.Int31n(2)) * time.Second)
count = temp
//lock ends here
mu.Unlock()
}
fmt.Println("Count after i="+strconv.Itoa(n)+" Count:", strconv.Itoa(count))
}
func main() {
//loop calling the process() 3 times
for i := 1; i < 4; i++ {
go process(i)
}
//delay to wait for the routines to complete
time.Sleep(25 * time.Second)
fmt.Println("Final Count:", count)
}
Nyní bude výstup
Count after i=3 Count: 21 Count after i=2 Count: 28 Count after i=1 Count: 30 Final Count: 30
Zde dostáváme očekávaný výsledek jako konečný výstup. Protože čtení příkazů, inkrementace a zpětný zápis počtu se provádí v mutexu.
Chyba při zpracování
Chyby jsou abnormální stavy, jako je zavření souboru, který není otevřen, otevření souboru, který neexistuje atd. Funkce obvykle vrací chyby jako poslední návratovou hodnotu.
Níže uvedený příklad vysvětluje více o chybě.
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")
}
Výstup bude:
open /invalid.txt: no such file or directory
Zde jsme se pokusili otevřít neexistující soubor a vrátilo to chybu do proměnné er. Pokud je soubor platný, bude chyba nulová
Vlastní chyby
Pomocí této funkce můžete vytvářet vlastní chyby. To se provádí pomocí New() chybového balíčku. Výše uvedený program přepíšeme, abychom využili vlastní chyby.
Spusťte níže uvedený 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)
}
}
Výstup bude:
Custom error message:File name is wrong
Zde area() vrací plochu čtverce. Pokud je vstup menší než 1, pak area() vrátí chybovou zprávu.
Čtení souborů
Soubory slouží k ukládání dat. Go nám umožňuje číst data ze souborů
Nejprve vytvořte soubor, data.txt, ve vašem aktuálním adresáři s níže uvedeným obsahem.
Line one Line two Line three
Nyní spusťte níže uvedený program, abyste viděli, že vytiskne obsah celého souboru jako výstup
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))
}
Zde data, err := ioutil.ReadFile(“data.txt”) načte data a vrátí sekvenci bajtů. Při tisku je převeden do formátu řetězce.
Psaní souborů
Uvidíte to 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
}
}
Zde se vytvoří soubor test.txt. Pokud soubor již existuje, bude obsah souboru zkrácen. Writeline() se používá k zápisu obsahu do souboru. Poté jste soubor zavřeli pomocí Close().
Cheat Sheet
V tomto tutoriálu Go jsme probrali
| Téma | Description | Syntax |
|---|---|---|
| Základní typy | Numerický, řetězec, bool | |
| Proměnné | Deklarujte a přiřazujte hodnoty proměnným | var typ název_proměnné var název_proměnné typ = hodnota var název_proměnné1, název_proměnné2 = hodnota1, hodnota2 název_proměnné := hodnota |
| Konstanty | Proměnné, jejichž hodnotu nelze po přiřazení změnit | konst proměnná = hodnota |
| Pro smyčku | Provádějte příkazy ve smyčce. | pro inicializační_výraz; hodnocení_výraz; iterační_výraz{ // jeden nebo více příkazů } |
| Pokud jinak | Je to podmíněné prohlášení | if podmínka{ // statement_1 Else {} // statement_2 } |
| přepnout | Podmíněné prohlášení s více případy | přepnout výraz { case value_1: prohlášení_1 case value_2: prohlášení_2 case value_n: prohlášení_n default: statement_default } |
| Řada | Pevná velikost pojmenované sekvence prvků stejného typu | arrayname := [velikost] typ {value_0,value_1,…,value_size-1} |
| Plátek | Část nebo segment pole | var název_části [] typ = název_pole[start:konec] |
| Funkce | Blok příkazů, který provádí konkrétní úkol | func název_funkce (typ parametru_1, typ parametru_n) return_type { //výroky } |
| Balíčky | Používají se k uspořádání kódu. Zvyšuje čitelnost kódu a jeho opětovné použití | importovat název_balíčku |
| Odložit | Odloží provádění funkce, dokud funkce, která obsahuje, nedokončí provádění | odložit název_funkce (seznam_parametrů) |
| Pointers | Ukládá paměťovou adresu jiné proměnné. | var název_proměnné *typ |
| Struktura | Uživatelsky definovaný datový typ, který sám obsahuje ještě jeden prvek stejného nebo jiného typu | zadejte název struktury struct { proměnná_1 typ_proměnné_1 proměnná_2 typ_proměnné_2 variable_n variable_n_type } |
| Metody | Metoda je funkce s argumentem příjemce | func (variable variabletype) methodName(seznam_parametrů) { } |
| Gorutine | Funkce, která může běžet současně s jinými funkcemi. | go function_name (seznam_parametrů) |
| Kanál | Způsob, jakým spolu funkce komunikují. Médium, na které jedna rutina umísťuje data a k níž přistupuje jiná rutina. | Prohlásit: ch := make(chan int) Odeslat data do kanálu: kanálová_proměnná <- název_proměnné Příjem z kanálu: název_proměnné := <- proměnná_kanálu |
| vybrat | Příkaz Switch, který funguje na kanálech. Případová prohlášení budou kanálovou operací. Když je některý z kanálů připraven s daty, provede se příkaz spojený s tímto případem | vybrat { případ x := <-kan1: fmt.Println(x) případ y := <-kan2: fmt.Println(y) } |
| Mutex | Mutex se používá, když nechcete povolit přístup k prostředku více podprogramům současně. Mutex má 2 způsoby – zamknout a odemknout | mutex.Lock() //výroky mutex.Unlock(). |
| Čtení souborů | Přečte data a vrátí sekvenci bajtů. | Data, err := ioutil.ReadFile(název souboru) |
| Zapsat soubor | Zapisuje data do souboru | l, err := f.WriteString(text_k_zápisu) |
