summaryrefslogtreecommitdiffhomepage
path: root/cs-cz/go.html.markdown
blob: b2fec30ffa4b968b37d6e256f3716507b4f1f7cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
---
name: Go
category: language
language: Go
filename: learngo-cs.go
lang: cs-cz
contributors:
    - ["Sonia Keys", "https://github.com/soniakeys"]
    - ["Christopher Bess", "https://github.com/cbess"]
    - ["Jesse Johnson", "https://github.com/holocronweaver"]
    - ["Quint Guvernator", "https://github.com/qguv"]
    - ["Jose Donizetti", "https://github.com/josedonizetti"]
    - ["Alexej Friesen", "https://github.com/heyalexej"]
    - ["Clayton Walker", "https://github.com/cwalk"]
translators:
    - ["Ondra Linek", "https://github.com/defectus/"]
---

Jazyk Go byl vytvořen, jelikož bylo potřeba dokončit práci. Není to poslední 
trend ve světě počítačové vědy, ale je to nejrychlejší a nejnovější způsob,
jak řešit realné problémy.

Go používá známé koncepty imperativních jazyků se statickým typováním.
Rychle se kompiluje a také rychle běží. Přidává snadno pochopitelnou
podporu konkurenčnosti, což umožňuje využít výhody multi-core procesorů a
jazyk také obsahuje utility, které pomáhají se škálovatelným programováním.

Go má již v základu vynikající knihovnu a je s ním spojená nadšená komunita.

```go
// Jednořádkový komentář
/* Několika
 řádkový komentář */

// Každý zdroják začíná deklarací balíčku (package)
// main je vyhrazené jméno, které označuje spustitelný soubor,
// narozdíl od knihovny
package main

// Importní deklarace říkají, které knihovny budou použity v tomto souboru.
import (
	"fmt"       // Obsahuje formátovací funkce a tisk na konzolu
	"io/ioutil" // Vstupně/výstupní funkce
	m "math"    // Odkaz na knihovnu math (matematické funkce) pod zkratkou m
	"net/http"  // Podpora http protokolu, klient i server.
	"strconv"   // Konverze řetězců, např. na čísla a zpět.
)

// Definice funkce. Funkce main je zvláštní, je to vstupní bod do programu.
// Ať se vám to líbí, nebo ne, Go používá složené závorky
func main() {
	// Println vypisuje na stdout.
	// Musí být kvalifikováno jménem svého balíčko, ftm.
	fmt.Println("Hello world!")

	// Zavoláme další funkci
	svetPoHello()
}

// Funkce mají své parametry v závorkách
// Pokud funkce nemá parametry, tak musíme stejně závorky uvést.
func svetPoHello() {
	var x int // Deklarace proměnné. Proměnné musí být před použitím deklarované
	x = 3     // Přiřazení hodnoty do proměnné
	// Existuje "krátká" deklarace := kde se typ proměnné odvodí, 
	// proměnná vytvoří a přiřadí se jí hodnota
	y := 4
	sum, prod := naucSeNasobit(x, y)        // Funkce mohou vracet více hodnot
	fmt.Println("sum:", sum, "prod:", prod) // Jednoduchý výstup
	naucSeTypy()                            // < y minut je za námi, je čas učit se víc!
}

/* <- začátek mnohořádkového komentáře
Funkce mohou mít parametry a (několik) návratových hodnot.
V tomto případě jsou `x`, `y` parametry a `sum`, `prod` jsou návratové hodnoty.
Všiměte si, že `x` a `sum` jsou typu `int`.
*/
func naucSeNasobit(x, y int) (sum, prod int) {
	return x + y, x * y // Vracíme dvě hodnoty
}

// zabudované typy a literáty.
func naucSeTypy() {
	// Krátká deklarace většinou funguje
	str := "Learn Go!" // typ řetězec.

	s2 := `"surový" literát řetězce
může obsahovat nové řádky` // Opět typ řetězec.

	// Můžeme použít ne ASCII znaky, Go používá UTF-8.
	g := 'Σ' // type runa, což je alias na int32 a ukládá se do něj znak UTF-8

	f := 3.14159 // float64, je IEEE-754 64-bit číslem s plovoucí čárkou.
	c := 3 + 4i  // complex128, interně uložené jako dva float64.

	// takhle vypadá var s inicializací
	var u uint = 7 // Číslo bez znaménka, jehož velikost záleží na implementaci,
	               // stejně jako int
	var pi float32 = 22. / 7

	// takto se převádí typy za pomoci krátké syntaxe
	n := byte('\n') // byte je jiné jméno pro uint8.

	// Pole mají fixní délku, které se určuje v době kompilace.
	var a4 [4]int           // Pole 4 intů, všechny nastaveny na 0.
	a3 := [...]int{3, 1, 5} // Pole nastaveno na tři hodnoty
	// elementy mají hodntu 3, 1 a 5

	// Slicy mají dynamickou velikost. Pole i slacy mají své výhody,
	// ale většinou se používají slicy.
	s3 := []int{4, 5, 9}    // Podobně jako a3, ale není tu výpustka.
	s4 := make([]int, 4)    // Alokuj slice 4 intů, všechny nastaveny na 0.
	var d2 [][]float64      // Deklarace slicu, nic se nealokuje.
	bs := []byte("a slice") // Přetypování na slice

	// Protože jsou dynamické, můžeme ke slicům přidávat za běhu
	// Přidat ke slicu můžeme pomocí zabudované funkce append().
	// Prvním parametrem je slice, návratová hodnota je aktualizovaný slice.
	s := []int{1, 2, 3}		// Výsledkem je slice se 3 elementy.
	s = append(s, 4, 5, 6)	// Přidány další 3 elementy. Slice má teď velikost 6.
	fmt.Println(s) // Slice má hodnoty [1 2 3 4 5 6]

	// Pokud chceme k poli přičíst jiné pole, můžeme předat referenci na slice,
	// nebo jeho literát a přidat výpustku, čímž se slicu "rozbalí" a přidá se k
	// původnímu slicu.
	s = append(s, []int{7, 8, 9}...) // druhým parametrem je literát slicu.
	fmt.Println(s)	// slice má teď hodnoty [1 2 3 4 5 6 7 8 9]

	p, q := naucSePraciSPameti() // Deklarujeme p a q jako typ pointer na int.
	fmt.Println(*p, *q)   // * dereferencuje pointer. Tím se vypíší dva inty.

	// Mapy jsou dynamické rostoucí asociativní pole, jako hashmapa, nebo slovník
	// (dictionary) v jiných jazycích
	m := map[string]int{"tri": 3, "ctyri": 4}
	m["jedna"] = 1

	// Napoužité proměnné jsou v Go chybou.
	// Použijte podtržítko, abychom proměnno "použili".
	_, _, _, _, _, _, _, _, _, _ = str, s2, g, f, u, pi, n, a3, s4, bs
	// Výpis promenné se počítá jako použití.
	fmt.Println(s, c, a4, s3, d2, m)

	naucSeVetveníProgramu() // Zpátky do běhu.
}

// narozdíl od jiných jazyků, v Go je možné mít pojmenované návratové hodnoty.
// Tak můžeme vracet hodnoty z mnoha míst funkce, aniž bychom uváděli hodnoty v
// return.
func naucSePojmenovaneNavraty(x, y int) (z int) {
	z = x * y
	return // z je zde implicitní, jelikož bylo pojmenováno.
}

// Go má garbage collector. Používá pointery, ale neumožňuje jejich aritmetiku.
// Můžete tedy udělat chybu použitím nil odkazu, ale ne jeho posunutím.
func naucSePraciSPameti() (p, q *int) {
	// Pojmenované parametry p a q mají typ odkaz na int.
	p = new(int) // Zabudované funkce new alokuje paměť.
	// Alokované místo pro int má hodnotu 0 a p už není nil.
	s := make([]int, 20) // Alokujeme paměť pro 20 intů.
	s[3] = 7             // Jednu z nich nastavíme.
	r := -2              // Deklarujeme další lokální proměnnou.
	return &s[3], &r     // a vezmeme si jejich odkaz pomocí &.
}

func narocnyVypocet() float64 {
	return m.Exp(10)
}

func naucSeVetveníProgramu() {
	// Výraz if vyžaduje složené závorky, ale podmínka nemusí být v závorkách.
	if true {
		fmt.Println("říkal jsme ti to")
	}
	// Formátování je standardizované pomocí utility "go fmt".
	if false {
		// posměšek.
	} else {
		// úšklebek.
	}
	// Použij switch, když chceš zřetězit if.
	x := 42.0
	switch x {
	case 0:
	case 1:
	case 42:
		// jednotlivé case nepropadávají. není potřeba "break"
	case 43:
		// nedosažitelné, jelikož už bylo ošetřeno.
	default:
		// implicitní větev je nepovinná.
	}
	// Stejně jako if, for (smyčka) nepoužívá závorky.
	// Proměnné definované ve for jsou lokální vůči smyčce.
	for x := 0; x < 3; x++ { // ++ je výrazem.
		fmt.Println("iterace", x)
	}
	// zde je x == 42.

	// For je jediná smyčka v Go, ale má několik tvarů.
	for { // Nekonečná smyčka
		break    // Dělám si legraci
		continue // Sem se nedostaneme
	}

	// Můžete použít klíčové slovo range pro iteraci nad mapami, poli, slicy,
	// řetězci a kanály.
	// range vrací jednu (kanál) nebo dvě hodnoty (pole, slice, řetězec a mapa).
	for key, value := range map[string]int{"jedna": 1, "dva": 2, "tri": 3} {
		// pro každý pár (klíč a hodnota) je vypiš
		fmt.Printf("klíč=%s, hodnota=%d\n", key, value)
	}

	// stejně jako for, := v podmínce if přiřazuje hodnotu
	// nejříve nastavíme y a pak otestujeme, jestli je y větší než x.
	if y := narocnyVypocet(); y > x {
		x = y
	}
	// Funkční literáty jsou tzv. uzávěry (closure)
	xBig := func() bool {
		return x > 10000 // odkazuje na x deklarované ve příkladu použití switch
	}
	x = 99999
	fmt.Println("xBig:", xBig()) // true
	x = 1.3e3                    // To udělá z x == 1300
	fmt.Println("xBig:", xBig()) // teď už false.

	// Dále je možné funkční literáty definovat a volat na místě jako parametr
	// funkce, dokavaď:
	// a) funkční literát je okamžitě volán pomocí (),
	// b) výsledek se shoduje s očekávaným typem.
	fmt.Println("Sečte + vynásobí dvě čísla: ",
		func(a, b int) int {
			return (a + b) * 2
		}(10, 2)) // Voláno s parametry 10 a 2
	// => Sečti a vynásob dvě čísla. 24

	// Když to potřebujete, tak to milujete
	goto miluji
miluji:

	naučteSeFunkčníFactory() // funkce vracející funkce je zábava(3)(3)
	naučteSeDefer()      // malá zajížďka k důležitému klíčovému slovu.
	naučteSeInterfacy() // Přichází dobré věci!
}

func naučteSeFunkčníFactory() {
	// Následující dvě varianty jsou stejné, ale ta druhá je praktičtější
	fmt.Println(větaFactory("létní")("Hezký", "den!"))

	d := větaFactory("letní")
	fmt.Println(d("Hezký", "den!"))
	fmt.Println(d("Líný", "odpoledne!"))
}

// Dekorátory jsou běžné v jiných jazycích. To samé můžete udělat v Go
// pomocí parameterizovatelných funkčních literátů.
func větaFactory(můjŘetězec string) func(před, po string) string {
	return func(před, po string) string {
		return fmt.Sprintf("%s %s %s", před, můjŘetězec, po) // nový řetězec
	}
}

func naučteSeDefer() (ok bool) {
	// Odloží (defer) příkazy na okamžik těsně před opuštěním funkce.
	// tedy poslední se provede první
	defer fmt.Println("odložené příkazy jsou zpravovaná v LIFO pořadí.")
	defer fmt.Println("\nProto je tato řádka vytištěna první")
	// Defer se běžně používá k zavírání souborů a tím se zajistí, že soubor
	// bude po ukončení funkce zavřen.
	return true
}

// definuje typ interfacu s jednou metodou String()
type Stringer interface {
	String() string
}

// Definuje pár jako strukturu se dvěma poli typu int x a y.
type pár struct {
	x, y int
}

// Definuje method pár. Pár tedy implementuje interface Stringer.
func (p pár) String() string { // p je tu nazýváno "Receiver" - přijímač
	// Sprintf je další veřejná funkce z balíčku fmt.
	// Pomocí tečky přistupujeme k polím proměnné p
	return fmt.Sprintf("(%d, %d)", p.x, p.y)
}

func naučteSeInterfacy() {
	// Složené závorky jsou "strukturální literáty. Vyhodnotí a inicializuje
	// strukturu. Syntaxe := deklaruje a inicializuje strukturu.
	p := pár{3, 4}
	fmt.Println(p.String()) // Volá metodu String na p typu pár.
	var i Stringer          // Deklaruje i jako proměnné typu Stringer.
	i = p                   // Toto je možné, jelikož oba implementují Stringer
	// zavolá metodu String(( typu Stringer a vytiskne to samé jako předchozí.
	fmt.Println(i.String())

	// Funkce ve balíčku fmt volají metodu String, když zjišťují, jak se má typ
	// vytisknout.
	fmt.Println(p) // Vytiskne to samé, jelikož Println volá String().
	fmt.Println(i) // Ten samý výstup.

	naučSeVariabilníParametry("super", "učit se", "tady!")
}

// Funcke mohou mít proměnlivé množství parametrů.
func naučSeVariabilníParametry(mojeŘetězce ...interface{}) {
	// Iterujeme přes všechny parametry
	// Potržítku tu slouží k ignorování indexu v poli.
	for _, param := range mojeŘetězce {
		fmt.Println("parameter:", param)
	}

	// Použít variadický parametr jako variadický parametr, nikoliv pole.
	fmt.Println("parametery:", fmt.Sprintln(mojeŘetězce...))

	naučSeOšetřovatChyby()
}

func naučSeOšetřovatChyby() {
	// ", ok" je metodou na zjištění, jestli něco fungovalo, nebo ne.
	m := map[int]string{3: "tri", 4: "ctyri"}
	if x, ok := m[1]; !ok { // ok bude false, jelikož 1 není v mapě.
		fmt.Println("není tu jedna")
	} else {
		fmt.Print(x) // x by bylo tou hodnotou, pokud by bylo v mapě.
	}
	// hodnota error není jen znamením OK, ale může říct více o chybě.
	if _, err := strconv.Atoi("ne-int"); err != nil { // _ hodnotu zahodíme
		// vytiskne 'strconv.ParseInt: parsing "non-int": invalid syntax'
		fmt.Println(err)
	}
	// Znovu si povíme o interfacech, zatím se podíváme na
	naučSeKonkurenčnost()
}

// c je kanál, způsob, jak bezpečně komunikovat v konkurenčním prostředí.
func zvyš(i int, c chan int) {
	c <- i + 1 // <- znamená "pošli" a posílá data do kanálu na levé straně.
}

// Použijeme funkci zvyš a konkurečně budeme zvyšovat čísla.
func naučSeKonkurenčnost() {
	// funkci make jsme již použili na slicy. make alokuje a inicializuje slidy,
	// mapy a kanály.
	c := make(chan int)
	// nastartuj tři konkurenční go-rutiny. Čísla se budou zvyšovat
	// pravděpodobně paralelně pokud je počítač takto nakonfigurován.
	// Všechny tři zapisují do toho samého kanálu.
	go zvyš(0, c) // go je výraz pro start nové go-rutiny.
	go zvyš(10, c)
	go zvyš(-805, c)
	// Přečteme si tři výsledky a vytiskeneme je..
	// Nemůžeme říct, v jakém pořadí výsledky přijdou!
	fmt.Println(<-c, <-c, <-c) // pokud je kanál na pravo, jedná se o "přijmi".

	cs := make(chan string)       // Další kanál, tentokrát pro řetězce.
	ccs := make(chan chan string) // Kanál kanálu řetězců.
	go func() { c <- 84 }()       // Start nové go-rutiny na posílání hodnot.
	go func() { cs <- "wordy" }() // To samé s cs.
	// Select má syntaxi jako switch, ale vztahuje se k operacím nad kanály.
	// Náhodně vybere jeden case, který je připraven na komunikaci.
	select {
        case i := <-c: // Přijatá hodnota může být přiřazena proměnné.
            fmt.Printf("je to typ %T", i)
        case <-cs: // nebo může být zahozena
            fmt.Println("je to řetězec")
        case <-ccs: // prázdný kanál, nepřipraven ke komunikaci.
      		fmt.Println("to se nestane.")
	}
	// V tomto okamžiku máme hodnotu buď z kanálu c nabo cs. Jedna nebo druhá
	// nastartovaná go-rutina skončila a další zůstane blokovaná.

	naučSeProgramovatWeb() // Go to umí. A vy to chcete taky.
}

// jen jedna funkce z balíčku http spustí web server.
func naučSeProgramovatWeb() {

	// První parametr ListenAndServe je TCP adresa, kde poslouchat.
	// Druhý parametr je handler, implementující interace http.Handler.
	go func() {
		err := http.ListenAndServe(":8080", pár{})
		fmt.Println(err) // neignoruj chyby
	}()

	requestServer()
}

// Umožní typ pár stát se http tím, že implementuje její jedinou metodu
// ServeHTTP.
func (p pár) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Servíruj data metodou http.ResponseWriter
	w.Write([]byte("Naučil ses Go za y minut!"))
}

func requestServer() {
	resp, err := http.Get("http://localhost:8080")
	fmt.Println(err)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	fmt.Printf("\nWebserver řekl: `%s`", string(body))
}
```

## Kam dále

Vše hlavní o Go se nachází na [oficiálních stránkách go](https://go.dev/).
Tam najdete tutoriály, interaktivní konzolu a mnoho materiálu ke čtení.
Kromě úvodu, [dokumenty](https://go.dev/doc/) tam obsahují jak psát čistý kód v Go
popis balíčků (package), dokumentaci příkazové řádky a historii releasů.

Také doporučujeme přečíst si definici jazyka. Je čtivá a překvapivě krátká. Tedy alespoň proti
jiným současným jazyků.

Pokud si chcete pohrát s Go, tak navštivte [hřiště Go](https://go.dev/play/p/r46YvCu-XX).
Můžete tam spouštět programy s prohlížeče. Také můžete [https://go.dev/play/](https://go.dev/play/) použít jako
[REPL](https://en.wikipedia.org/wiki/Read-eval-print_loop), kde si v rychlosti vyzkoušíte věci, bez instalace Go.

Na vašem knižním seznamu, by neměly chybět [zdrojáky stadardní knihovny](https://go.dev/src/).
Důkladně popisuje a dokumentuje Go, styl zápisu Go a Go idiomy. Pokud kliknete na [dokumentaci](https://go.dev/pkg/)
tak se podíváte na dokumentaci.

Dalším dobrým zdrojem informací je [Go v ukázkách](https://gobyexample.com/).

Go mobile přidává podporu pro Android a iOS. Můžete s ním psát nativní mobilní aplikace nebo knihovny, které půjdou
spustit přes Javu (pro Android), nebo Objective-C (pro iOS). Navštivte [web Go Mobile](https://go.dev/wiki/Mobile)
pro více informací.