Obsah
1. Systém modulů v programovacím jazyce Go
3. Největší nevýhody původního konceptu
5. Balíčky, moduly a repositáře
6. Vytvoření prvního jednoduchého modulu
7. Zdrojový kód modulu, překlad a spuštění modulu
8. Přidání balíčku, na němž modul závisí
10. Struktura adresáře $GOPATH po stažení balíčku
12. Problematika potencionálního rozbití API
13. Změna minoritní verze modulu
14. Změna majoritní verze modulu
15. Vytvoření externí knihovny s několika majoritními verzemi a jednou verzí minoritní
16. Použití externí knihovny s více majoritními verzemi v demonstračním projektu
18. Změna demonstračního příkladu – využití sémantického importu
19. Repositáře s demonstračními příklady
1. Systém modulů v programovacím jazyce Go
V dnešní části seriálu o programovacím jazyce Go se seznámíme se základními vlastnostmi oficiálního systému modulů, na který mnozí vývojáři poměrně dlouho čekali. V původních verzích jazyka Go se totiž nepočítalo s tím, že by vyvíjené aplikace mohly vyžadovat konkrétní verze balíčků (třetích stran) a už vůbec ne s tím, že se při vývoji jednotlivých balíčků (typicky knihoven) může měnit jejich API. Oficiální, ovšem v reálném světě těžko zajistitelnou doktrínou bylo, že balíček (package) určitého jména nikdy nezmění své API a pokud by ke změně mělo dojít, měl by se balíček přejmenovat. Jednalo se o dosti problematický rys celého ekosystému jazyka Go, který byl jen do určité míry řešen externími nástroji, jichž za relativně krátkou dobu existence Go vzniklo prakticky nepřeberné množství. Tento stav však začal být neúnosný a možná podstatným způsobem zbrzdil rozšíření programovacího jazyka Go (už jen z toho důvodu, že mnohé ostatní ekosystémy do značné míry tento problém mají vyřešený: Maven, npm, pip, Cargo atd.):
dep was the „official experiment.“ The Go toolchain, as of 1.11, has adopted an approach that sharply diverges from dep. As a result, we are continuing development of dep, but gearing work primarily towards the development of an alternative prototype for versioning behavior in the toolchain.
Jak je z předchozí citace zřejmé, objevil se v toolchainu programovacího jazyka Go verze 1.11 (i když jen v „preliminary“ variantě) oficiální systém pro práci s takzvanými moduly. Tento systém je postupně stabilizován, takže si v dnešním článku ukážeme jeho použití s prozatím nejnovějším oficiálním vydáním programovacího jazyka Go – Go verze 1.13.
2. Původní koncept jazyka Go
Nejdříve si alespoň ve stručnosti připomeňme, jak vlastně vypadal původní koncept programovacího jazyka Go při práci s balíčky (package), a to jak s balíčky lokálními, tak i s externími knihovnami. Již v úvodním článku tohoto seriálu jsme si řekli, že při instalaci programovacího jazyka Go je vhodné nastavit proměnnou GOPATH, například na adresář ~/home/go. Ve skutečnosti je problematika proměnné prostředí GOPATH a jejího významu poněkud složitější, protože tato proměnná by měla obsahovat absolutní (!) cestu k adresáři, který má či bude mít následující strukturu:
. ├── bin │ ├── │ └── ├── pkg │ ├── │ └── └── src ├── ├── └──
Celý adresář se v dokumentaci nazývá pracovní plocha (workspace) a obsahuje tři podadresáře pojmenované src, pkg a bin. Z pohledu vývojáře je nejdůležitější podadresář src, v němž jsou typicky uloženy repositáře (repository) a v každém repositáři je umístěn libovolný počet balíčků (package). V balíčcích už nalezneme jednotlivé zdrojové soubory .go, pomocné skripty, datové soubory, dokumentaci, testy atd. Workspace představovaný adresářem nazvaným go, v němž jsou umístěny tři repositáře, může vypadat například následovně:
. └── go ├── bin ├── pkg └── src ├── repository1 │ ├── hello1 │ │ └── hello.go │ └── hello2 │ └── hello.go ├── repository2 └── repository3
Vidíme, že v repositáři pojmenovaném repository1 jsou umístěny dva balíčky, které mají názvy hello1 a hello2, přičemž v každém balíčku je jediný zdrojový soubor, který je (čistě náhodou) shodně pojmenován hello.go (což v tomto případě nevadí, protože nedojde ke kolizi).
Soubor hello.go může vypadat následovně:
package main func main() { println("repository1: Hello world!") }
Instalace externích knihoven, na nichž mohla nějaká aplikace záviset, se prováděla (a stále může provádět) příkazem go get.
Pokud například budeme potřebovat vypočítat Levenštejnovu vzdálenost dvou řetězců (což se provádí poměrně často například při implementaci uživatelsky přívětivé funkce Search), můžeme pro tento účel použít knihovnu/balíček s názvem levenshtein a s cestou github.com/agext/levenshtein, která je dostupná na GitHubu, konkrétně na adrese https://github.com/agext/levenshtein (součástí plné cesty balíčku je skutečně i „github.com“).
Balíček agext/levenshtein se instaluje velmi snadno, a to již výše zmíněným příkazem go get, kterému předáme jméno repositáře s balíčkem (ovšem vynechá se protokol!):
$ go get github.com/agext/levenshtein
Pokud chcete vidět, jaké operace se provádí, přidejte přepínač -v:
$ go get -v github.com/agext/levenshtein github.com/agext/levenshtein (download)
Nyní by měla adresářová struktura ~/go (přesněji řečeno adresář, na který ukazuje proměnná prostředí $GOPATH) vypadat zhruba následovně:
. . └── go ├── bin ├── pkg │ └── linux_amd64 │ └── github.com │ └── agext │ └── levenshtein.a └── src ├── github.com ├── agext │ └── levenshtein │ ├── DCO │ ├── levenshtein.go │ ├── levenshtein_test.go │ ├── LICENSE │ ├── MAINTAINERS │ ├── NOTICE │ ├── params.go │ ├── params_test.go │ └── README.md ├── repository1 │ ├── hello1 │ │ └── hello.go │ └── hello2 │ └── hello.go ├── repository2 └── repository3 15 directories, 16 files
Povšimněte si, že se balíček nainstaloval jak do podadresáře src (vlastní zdrojové kódy, testy, licence, další dokumentace), tak i do podadresáře pkg (binární knihovna určená pro slinkování s kódem výsledných aplikací). Po instalaci je součástí cesty k balíčku skutečně i prefix github.com, protože zdrojové kódy balíčku leží v podadresáři src/github.com/agext/levenshtein.
Příkaz go list by nyní měl ukázat informace i o nově nainstalované knihovně agext/levenshtein:
$ go list ... ... ... ... github.com/agext/levenshtein ... ... ...
Podobně uvidíme základní informace o balíčku i na dynamicky generovaných stránkách s dokumentací.
3. Největší nevýhody původního konceptu
V předchozí kapitole jsme si ukázali, že i v původním Go, resp. přesněji řečeno při použití původního konceptu práce s balíčky, bylo možné alespoň nějakým způsobem standardně pracovat s externími balíčky a knihovnami, na nichž závisela vyvíjená aplikace. Ovšem současně měl tento systém hned několik špatných vlastností, mezi které patří zejména:
- Všechny projekty, nezávisle na tom, jakého mají zákazníka a popř. pro koho jsou vytvářeny, musí být umístěny ve stejném adresáři, na nějž ukazuje proměnná prostředí $GOPATH. Teoreticky je sice možné $GOPATH přepínat, ale jedná se o dosti křehké řešení.
- Prakticky žádným rozumným způsobem není řešeno verzování balíčků. To znamená, že není možné specifikovat verzi balíčku, s nímž budeme potřebovat pracovat a tím pádem ani není možné použít dvě verze stejného balíčku. Tuto vlastnost ještě více umocňuje bod číslo 1, tedy umístění všech zdrojových kódů v jediné adresářové struktuře.
- Všechny externí balíčky je nutné nějakým způsobem udržovat, zjišťovat případná CVE atd. Ovšem jak již plyne z bodů #1 a #2, je možné, že updatem jediného balíčku se může rozbít prakticky libovolná vyvíjená aplikace – typický „dependency hell“.
- Pokud externí balíček závisí na dalších balíčcích, musíme řešit i takzvanétranzitivní závislosti, s jejichž správou jednoduchý systém založený na go get příliš nepočítá.
Dále představený standardní systém balíčků se výše uvedené problémy snaží do velké míry vyřešit.
4. Instalace Go verze 1.13
Doslova před několika dny bylo vydáno Go verze 1.13, viz též https://golang.org/doc/devel/release.html. Všechny dnes popisované ukázky a demonstrační příklady již budou tuto verzi používat (už jen z toho důvodu, že oficiálně byly moduly v Go 1.11 a Go 1.12 jen ve stavu „preliminary“), takže si v této kapitole ve stručnosti ukážeme, jakým způsobem je možné Go 1.13 nainstalovat, a to i v případě, kdy tato verze ještě není dostupná v balíčcích vaší Linuxové distribuce. Předpokladem je, že předchozí verze Go byla nainstalována do adresáře /opt/go, ovšem pochopitelně změna cíle instalace je triviální.
Nejprve se zbavíme předchozí verze:
$ rm -rf /opt/go nebo $ sudo rm -rf /opt/go
Dále stáhneme novou verzi Go 1.13, zde konkrétně pro 64bitovou platformu x86–64:
$ wget https://dl.google.com/go/go1.13.linux-amd64.tar.gz --2019-09-04 15:50:48-- https://dl.google.com/go/go1.13.linux-amd64.tar.gz Resolving dl.google.com (dl.google.com)... 2a00:1450:4014:801::200e, 216.58.201.110 Connecting to dl.google.com (dl.google.com)|2a00:1450:4014:801::200e|:443... failed: No route to host. Connecting to dl.google.com (dl.google.com)|216.58.201.110|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 120050424 (114M) [application/octet-stream] Saving to: ‘go1.13.linux-amd64.tar.gz’ go1.13.linux-amd64.tar.gz 100%[==============================================================================>] 114.49M 68.6MB/s in 1.7s 2019-09-04 15:50:50 (68.6 MB/s) - ‘go1.13.linux-amd64.tar.gz’ saved [120050424/120050424]
Stažený tarball rozbalíme, a to se specifikací cíle instalace, jímž je adresář /opt/:
$ tar xvfz go1.13.linux-amd64.tar.gz -C /opt/
V tomto adresáři by se měla vytvořit struktura s celým toolingem programovacího jazyka Go 1.13:
$ tree -d /opt -L 2 /opt └── go ├── api ├── bin ├── doc ├── lib ├── misc ├── pkg ├── src └── test 9 directories
Přesvědčíme se, že adresář /opt/go/bin je na PATH:
$ echo $PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/home/tester/bin:/opt/go/bin:/home/tester/.local/bin:/home/tester/bin
Dále se přesvědčíme, zda je nastavena proměnná GOPATH, a to z důvodu zpětné kompatibility se starším systémem správy balíčků, který jsme si popsali ve druhé kapitole:
$ echo $GOPATH /home/tester/go
V případě, že je PATH nastavená korektně, měl by následující příkaz vypsat verzi právě nově nainstalovaného jazyka Go:
$ go version go version go1.13 linux/amd64
5. Balíčky, moduly a repositáře
Při práci s moduly v programovacím jazyku Go se rozlišuje mezi třemi termíny – balíčkem, modulem a repositářem:
- Balíček je představován adresářem obsahujícím zdrojové kódy, většinou i včetně testů. Zdrojové kódy v jednom adresáři většinou začínají stejnou deklarací package.
- Modul se obecně může skládat z většího množství balíčků. Všechny tyto balíčky jsou poskytovány a vydávány společně. V nejjednodušším případě modul obsahuje jediný balíček (což bude i náš případ).
- Repositář obecně obsahuje více modulů (většinou jediný modul). V našich příkladech budeme počítat s tím, že v jednom repositáři je jediný modul popř. více verzí jednoho modulu.
6. Vytvoření prvního jednoduchého modulu
Nyní by již mělo být vše připravené pro otestování standardního systému pro práci s moduly. Všechny další příklady budou vytvářeny v adresáři ~/src, což konkrétně znamená, že se vyhneme použití adresáře, na který ukazuje proměnná prostředí GOPATH.
Nejprve provedeme inicializaci modulu, což zajistí příkaz go mod init, kterému předáme jméno repositáře, v němž může být modul umístěn. Ovšem platí, že pokud tento modul nebude použitý jiným modulem, nemusí být jméno repositáře shodné se skutečným repositářem (ovšem později si tím zbytečně zkomplikujeme další práci, proto je lepší rozlišovat pouze sémantické verze).
Náš modul se bude jmenovat github.com/tisnik/my-first-module, takže se jeho inicializace provede následovně:
$ go mod init github.com/tisnik/my-first-module go: creating new go.mod: module github.com/tisnik/my-first-module
Tento příkaz provede jen jedinou operaci – do aktuálního adresáře přidá soubor pojmenovaný go.mod, v němž budou (prozatím) pouze dva řádky – vlastní jméno modulu a taktéž verze programovacího jazyka Go, resp. přesněji řečeno celého toolchainu tohoto jazyka:
$ cat go.mod module github.com/tisnik/my-first-module go 1.13
7. Zdrojový kód modulu, překlad a spuštění modulu
Nyní vytvoříme zdrojový kód modulu. Bude se jednat o jednoduchou aplikaci, v níž je deklarována funkce Add, kterou si odzkoušíme na čtyřech skupinách celých čísel. Vzhledem k tomu, že se skutečně má jednat o spustitelnou aplikaci, použijeme, jak je zvykem, balíček main a deklarovat budeme muset i funkci main:
package main import "fmt" func Add(x int, y int) int { return x + y } func main() { fmt.Println(Add(0, 0)) fmt.Println(Add(1, 0)) fmt.Println(Add(1, 2)) fmt.Println(Add(-1, 2)) }
Modul přeložíme běžným způsobem, tj. příkazem go build:
$ go build -o adder
A pro jistotu otestujeme, že výsledná aplikace (spustitelný binární soubor) je skutečně plně funkční:
$ ./adder 0 1 3 1
8. Přidání balíčku, na němž modul závisí
Nyní si ukažme, jakým způsobem se situace změní ve chvíli, kdy do našeho projektu přidáme balíček, na němž projekt závisí. Samotný balíček bude velmi jednoduchý (až triviální) a nalezneme ho na adrese https://github.com/tisnik/intvalues. V tomto balíčku je umístěn jediný zdrojový soubor, který pro jednoduchost obsahuje několik důležitých celočíselných konstant, které později v našem projektu použijeme, abychom nemuseli používat „magické konstanty“:
package intvalues const Zero = 0 const One = 0 const MaxInt = int(^uint(0) >> 1) const MinInt = -MaxInt - 1
Přidání externího balíčku, na němž náš projekt závisí, je při použití modulů většinou zcela triviální, protože do zdrojového kódu pouze postačuje přidat příslušný import se jménem balíčku včetně cesty na GitHubu či na jiném podporovaném externím repositáři (z tohoto pohledu je GitHub skutečně chápán jako repositář s verzovanými balíčky):
import "github.com/tisnik/intvalues"
V našem konkrétním příkladu bude zdrojový kód vypadat následovně (nový import je zvýrazněn):
package main import ( "fmt" "github.com/tisnik/intvalues" ) func Add(x int, y int) int { return x + y } func main() { fmt.Println(Add(intvalues.Zero, intvalues.Zero)) fmt.Println(Add(intvalues.One, 0)) fmt.Println(Add(1, 2)) fmt.Println(Add(-1, 2)) }
Před spuštěním popř. před překladem takto upraveného příkladu se můžeme podívat na strukturu adresáře ~/go, popř. toho adresáře, na který ukazuje proměnná prostředí se jménem GOPATH. Tento adresář může být prázdný, popř. může obsahovat některé starší projekty (ty nás ovšem nemusí příliš zajímat):
. ├── bin ├── pkg └── src
Můžeme se pokusit upravený příklad (s externí závislostí) spustit, a to klasicky příkazem go run::
$ go run adder.go go: finding github.com/tisnik/intvalues latest go: downloading github.com/tisnik/intvalues v0.0.0-20190905132008-dad69ec19589 go: extracting github.com/tisnik/intvalues v0.0.0-20190905132008-dad69ec19589 0 0 3 1
Z předchozího výpisu je patrné, že ještě před samotným spuštěním přeloženého projektu nástroje jazyka Go stáhly balíček, na němž náš projekt závisí. To znamená, že už není zapotřebí používat příkaz go get, který má problematické chování! Dále si povšimněte, jak nástroje Go zajistily verzi externího balíčku. Tuto verzi jsme nikde nespecifikovali (tedy ani v projektu ani v závislém balíčku), proto bylo číslo verze uměle vytvořeno ze dvou dostupných údajů:
- Časového razítka posledního commitu (2019–09–05 přibližně v 13:20)
- Hashe posledního commitu (plný hash je commit dad69ec1958979dd2b25b68e862550c1a29f17da)
Spuštěním či překladem projektu navíc došlo i ke změně obsahu souboru go.mod, v němž se kromě předchozích dvou řádků popsaných výše objevil nový řádek require obsahující nám již známé údaje o přidané závislosti i její přesné verzi (zde automaticky vygenerované):
module github.com/tisnik/my-first-module go 1.13 require github.com/tisnik/intvalues v0.0.0-20190905132008-dad69ec19589 // indirect
9. Soubor go.sum
Současně při překladu aplikace v adresáři s projektem automaticky vznikl i nový soubor se jménem go.sum. Obsah tohoto souboru by v našem triviálním demonstračním příkladu měl vypadat následovně:
github.com/tisnik/intvalues v0.0.0-20190905132008-dad69ec19589 h1:AAvNlAqsqYEVQUG4hHFNJOvvKVRh8DC+OI0wuEn0v7Y= github.com/tisnik/intvalues v0.0.0-20190905132008-dad69ec19589/go.mod h1:Pc260EFOSnRzU0A/CN2vfBETjFJ4B+LijhuPYjfUWrA=
Obecná struktura souboru go.sum dodržuje formát:
<modul> <verze>[/go.mod] <hash>
Každý modul (zde externí balíček), na němž projekt závisí, je zapsán na dvou po sobě jdoucích řádcích. Na prvním řádku je na konci uveden otisk (hash) stromu se soubory modulu, na druhém řádku pak hash souboru go.mod obsaženého přímo v modulu či automaticky vygenerovaného nástroji jazyka Go (pokud tento soubor v repositáři s modulem není uložen).
10. Struktura adresáře $GOPATH po stažení balíčku
Po automatickém stažení balíčku github.com/tisnik/intvalues a spuštění našeho demonstračního projektu se struktura adresáře, na který ukazuje proměnná prostředí $GOPATH dosti rapidním způsobem změní. V případě, že tento adresář byl před překladem projektu prázdný, měl by po jeho překladu vypadat zhruba následovně:
. ├── bin ├── pkg │ ├── mod │ │ ├── cache │ │ │ ├── download │ │ │ │ ├── github.com │ │ │ │ │ └── tisnik │ │ │ │ │ └── intvalues │ │ │ │ │ └── @v │ │ │ │ │ ├── list │ │ │ │ │ ├── list.lock │ │ │ │ │ ├── v0.0.0-20190905132008-dad69ec19589.info │ │ │ │ │ ├── v0.0.0-20190905132008-dad69ec19589.lock │ │ │ │ │ ├── v0.0.0-20190905132008-dad69ec19589.mod │ │ │ │ │ ├── v0.0.0-20190905132008-dad69ec19589.zip │ │ │ │ │ └── v0.0.0-20190905132008-dad69ec19589.ziphash │ │ │ │ └── sumdb │ │ │ │ └── sum.golang.org │ │ │ │ ├── lookup │ │ │ │ │ └── github.com │ │ │ │ │ └── tisnik │ │ │ │ │ └── intvalues@v0.0.0-20190905132008-dad69ec19589 │ │ │ │ └── tile │ │ │ │ └── 8 │ │ │ │ ├── 0 │ │ │ │ │ └── 668.p │ │ │ │ │ └── 214 │ │ │ │ ├── 1 │ │ │ │ │ └── 002.p │ │ │ │ │ └── 156 │ │ │ │ └── 2 │ │ │ │ └── 000.p │ │ │ │ └── 2 │ │ │ └── lock │ │ └── github.com │ │ └── tisnik │ │ └── intvalues@v0.0.0-20190905132008-dad69ec19589 │ │ ├── intvalues.go │ │ └── README.md │ └── sumdb │ └── sum.golang.org │ └── latest └── src 28 directories, 16 files
Vidíme, že vznikl celý nový podadresář pkg/mod, v němž můžeme nalézt jak vlastní zdrojový kód staženého balíčku, tak i množství souborů s metadaty o verzi balíčku, jeho otisku (přesněji řečeno otiscích) atd. Tento podadresář je kdykoli možné smazat, protože se jeho struktura automaticky obnoví při novém překladu vyvíjených aplikací (ovšem s tím, že se metadata znovu zjistí z externích repositářů).
11. Verzování balíčků
Vlastnosti systému modulů, které jsme si až doposud popsali, jsou sice určitým pokrokem oproti použití klasického go get, ovšem celou sílu nového konceptu doceníme až tehdy, když začneme pracovat s verzemi balíčků (a modulů). Systém modulů nám totiž umožní použít konkrétní verzi balíčku a do určité míry řeší i tranzitivní závislosti, tj. situaci, kdy knihovna A vyžaduje balíček Z ve verzi 1.0 a knihovna B taktéž balíček Z, ovšem tentokrát ve verzi 2.0. Některé ukázky budou uvedeny v navazujícím textu.
12. Problematika potencionálního rozbití API
Mohlo by se zdát, že na konkrétní verzi modulu/balíčku nemusí záležet, protože nové verze buď „pouze“ opravují chyby verze předchozí, nebo přidávají další funkcionalitu. Na základě tohoto pohledu by tedy bylo jen výhodné slepě updatovat všechny moduly na nejnovější verzi, protože ta by měla být nejstabilnější a měla by obsahovat plnou funkcionalitu verzí předchozích. Ve skutečnosti tomu tak pochopitelně být nemusí, protože mezi jednotlivými verzemi balíčků (představme si zde nějakou knihovnu) může dojít ke změně jejího API, ať již přidáním/ubráním parametrů funkcí a metod, tak i mnohdy změnou celé filozofie ovládání. Tento problém, který ostatně musí řešit všechny balíčkovací systémy pro další programovací jazyky, je v Go řešen s využitím známého sémantického verzování [1], kde je verze balíčku popř. modulu zapsána trojicí celý čísel – majoritní verze.minoritní verze.číslo patche.
13. Změna minoritní verze modulu
V ekosystému programovacího jazyka Go (ovšem nejenom zde) se předpokládá, že se oficiální aplikační programové rozhraní modulu s minoritní verzí nemění. Může se pochopitelně do určité míry měnit konkrétní chování (ostatně i oprava chyby mění chování), ovšem exportované konstanty, proměnné, datové typy, funkce a metody by alespoň měly mít zachovánu svoji signaturu a sémantiku chování. Otázkou zůstává, zda má být API zcela neměnné, nebo zda je do něj možné přidávat další funkce a metody. Samotné přidání – pokud se ovšem nejedná o rozdělení činnosti původní jediné funkce do funkcí dvou – by v Go nemělo vadit, už jen z toho důvodu, že se zde nepoužívá koncept tříd a OOP postaveného na třídách a explicitně implementovaných rozhraní.
14. Změna majoritní verze modulu
Zcela jiná situace nastane ve chvíli, kdy se změní majoritní verze modulu. V tomto případě se (obecně) předpokládá, že nová verze může mít API zcela odlišné od API předchozí verze a tudíž není možné bez dalších úprav vyvíjené aplikace na tuto verzi přejít. V programovacím jazyce Go existuje vcelku elegantní řešení tohoto problému, které spočívá v použití takzvaných sémantických importů, s nimiž se seznámíme v sedmnácté kapitole.
15. Vytvoření externí knihovny s několika majoritními verzemi a jednou verzí minoritní
Pro otestování funkčnosti systému modulů v programovacím jazyku Go byl vytvořen repositář https://github.com/tisnik/integers, v němž je uložen jediný modul s jediným balíčkem (viz též pátou kapitolu, kde jsou vztahy mezi těmito pojmy vysvětleny. V tomto repositáři byly příkazem:
$ git tag -a _verze_ -m "zpráva"
vytvořeny celkem čtyři tagy označující čtyři různé stavy repositáře. Navíc byly ze všech čtyř tagů vytvořena vydání (release), jejichž seznam naleznete na stránce https://github.com/tisnik/integers/releases.
Informace o vydáních našeho testovacího balíčku
Verzi 1.0.0 označenou tagem v1.0.0 naleznete na adrese https://github.com/tisnik/integers/releases/tag/v1.0.0. V této verzi je vydán balíček nazvaný integers s dvojicí celočíselných konstant MaxInt a MinInt:
package integers const MaxInt = int(^uint(0) >> 1) const MinInt = -MaxInt - 1
Další verze je minoritní, což znamená, že její první číslo je stále 1. Konkrétně se jedná o verzi 1.1.0 s tagem v1.1.0 a najdeme ji na adrese https://github.com/tisnik/integers/releases/tag/v1.1.0. API v tomto případě bylo rozšířeno o další dvě celočíselné konstanty Zero a One:
package integers const MaxInt = int(^uint(0) >> 1) const MinInt = -MaxInt - 1 const Zero = 0 const One = 1
Další verze nese číslo 2.0.0 a došlo zde ke změně API, která může vést k tomu, že bude zapotřebí upravit vyvíjenou aplikaci (konkrétně byly odstraněny konstanty MinInt a MaxInt). Tag této verze je podle očekávání v2.0.0 a další podrobnosti najdete na adrese https://github.com/tisnik/integers/releases/tag/v2.0.0:
package integers const Zero = 0 const One = 1
Navíc byla vydána i verze 4.0, ovšem touto verzí se budeme zabývat až v sedmnácté kapitole.
16. Použití externí knihovny s více majoritními verzemi v demonstračním projektu
Nyní si zkusme vytvořit jednoduchý demonstrační projekt, který bude výše uvedený repositář a v něm uložený balíček používat. V tomto projektu nejdříve jednoduše naimportujeme balíček github.com/tisnik/integers a následně použijeme konstanty v tomto balíčku deklarované:
package main import ( "fmt" "github.com/tisnik/integers" ) func Add(x int, y int) int { return x + y } func main() { fmt.Println(Add(integers.Zero, integers.Zero)) fmt.Println(Add(integers.One, 0)) fmt.Println(Add(integers.MaxInt, integers.MinInt)) fmt.Println(Add(1, 2)) fmt.Println(Add(-1, 2)) }
V případě, že by byla vydána pouze verze 1.0.0 našeho testovacího balíčku, vypadal by pokus o překlad takto:
$ go build go: downloading github.com/tisnik/integers v1.0.0 go: extracting github.com/tisnik/integers v1.0.0 go: finding github.com/tisnik/integers v1.0.0 ./adder.go:13:18: undefined: integers.Zero ./adder.go:14:18: undefined: integers.One
Vidíme, že se systém jazyka Go pokusil o stažení poslední stabilní verze (1.0.0), ve které ovšem nejsou specifikovány konstanty Zero a One, takže překlad skončí s chybou.
Ve chvíli, kdy je vydána verze 1.1.0 (a je automaticky označena jako „latest version“), se dočkáme bezchybného překladu, protože všechny čtyři potřebné konstanty existují pouze v této verzi:
$ go build go: downloading github.com/tisnik/integers v1.1.0 go: extracting github.com/tisnik/integers v1.1.0 go: finding github.com/tisnik/integers v1.1.0
Ovšem může taktéž nastat situace, kdy již byla vydána verze 2.0.0, která původní API rozbije. Potom se opět překlad nepovede, tentokrát ovšem kvůli tomu, že chybí konstanty MinInt a MaxInt:
$ go build go: finding github.com/tisnik/integers v2.0.0 ./adder.go:15:18: undefined: integers.MaxInt ./adder.go:15:35: undefined: integers.MinInt
Zajímavé bude se v tomto okamžiku podívat na obsah souboru go.sum. Ten by měl obsahovat následující záznamy (tři dvojice verzí):
$ cat go.sum github.com/tisnik/integers v1.0.0 h1:hTvDeOyjmLt1BJqeQmSnJNOlSst9LthLfQnU53h0Ik0= github.com/tisnik/integers v1.0.0/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU= github.com/tisnik/integers v1.1.0 h1:xygWKRg5EGDS/PZyR7SuhYp3PXQTkRdY6TcPsOd4iio= github.com/tisnik/integers v1.1.0/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU= github.com/tisnik/integers v2.0.0+incompatible h1:wJnU/uiLwDL1CWiDyhb+lhS/ByAkfWlAsRlh54wL5mc= github.com/tisnik/integers v2.0.0+incompatible/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU=
Všechny prozatím stažené a dostupné verze vypíše příkaz:
$ go list -m -versions github.com/tisnik/integers github.com/tisnik/integers v1.0.0 v1.1.0 v2.0.0+incompatible
17. Sémantické importy
Pro řešení kolizí mezi více majoritními verzemi balíčku (či modulu) s rozdílným API podporuje programovací jazyk Go i koncept takzvaných sémantických importů. Jedná se o téma na samostatný článek, ovšem již dnes si můžeme ukázat, jak snadno je možné upravit náš balíček tak, aby se mohl sémantický import provést. Do repositáře s balíčkem vložíme soubor go.mod vytvořený příkazem go mod init (ten jsme až doposud nepotřebovali, protože náš balíček na žádném dalším balíčku nezávisel). Důležité je, že nově vytvořený soubor go.mod vypadá takto:
module github.com/tisnik/integers/v4 go 1.13
Povšimněte si, že jsme jméno modulu rozšířili o suffix /v4. Po přidání tohoto souboru do repositáře byl vytvořen nový tag:
$ git tag -a v4.0.0 -m "Version 4.0.0 as module"
A z něj byla vydána nová verze balíčku.
18. Změna demonstračního příkladu – využití sémantického importu
Nyní musíme upravit i náš demonstrační příklad, a to tak, že změníme jméno importovaného modulu přidáním suffixu /v4:
package main import ( "fmt" "github.com/tisnik/integers/v4" ) func Add(x int, y int) int { return x + y } func main() { fmt.Println(Add(integers.Zero, integers.Zero)) fmt.Println(Add(integers.One, 0)) //fmt.Println(Add(integers.MaxInt, integers.MinInt)) fmt.Println(Add(1, 2)) fmt.Println(Add(-1, 2)) }
V této chvíli je možné používat API verze 4.0.0, které obecně nemusí být kompatibilní se starším API. Povšimněte si, že další úpravy zdrojového kódu příkladu nebyly nutné, tj. stále používáme konstanty integers.Zero atd. a nikoli (například) v4.Zero.
Na závěr se podívejme, jak se změnil obsah souboru go.sum po vydání čtvrté verze s podporou sémantického importu:
$ cat go.sum github.com/tisnik/integers v1.0.0 h1:hTvDeOyjmLt1BJqeQmSnJNOlSst9LthLfQnU53h0Ik0= github.com/tisnik/integers v1.0.0/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU= github.com/tisnik/integers v1.1.0 h1:xygWKRg5EGDS/PZyR7SuhYp3PXQTkRdY6TcPsOd4iio= github.com/tisnik/integers v1.1.0/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU= github.com/tisnik/integers v2.0.0+incompatible h1:wJnU/uiLwDL1CWiDyhb+lhS/ByAkfWlAsRlh54wL5mc= github.com/tisnik/integers v2.0.0+incompatible/go.mod h1:qfkSORAgW6E8jwfni4JdVE4AKzFvQs7239NSw/cf+fU= github.com/tisnik/integers/v4 v4.0.0 h1:ynI0tihEdy9TGA5hbQFNcJHekTEBE5sgDJhfyIifGdA= github.com/tisnik/integers/v4 v4.0.0/go.mod h1:O74h6zHFVUNb1K13mibPK1GGgRgJqKdEpp5Z6vay2Pc=
Vidíme, že na posledních dvou řádcích se objevila informace o nové verzi, včetně suffixu /v4.
19. Repositáře s demonstračními příklady
V dnešním článku jsme použili hned několik repositářů obsahujících jak demonstrační příklady, tak i repositáře s balíčky (jak verzovanými, tak i neverzovanými). Odkazy na jednotlivé repositáře jsou uvedeny v následující tabulce:
# | Repositář | Stručný popis | Adresa na GitHubu |
---|---|---|---|
1 | go-1st-module | první testovaný modul | https://github.com/tisnik/go-1st-module |
2 | go-2nd-module | druhý testovaný modul | https://github.com/tisnik/go-2nd-module |
3 | intvalues | repositář s jedinou verzí balíčku intvalues | https://github.com/tisnik/intvalues |
4 | integers | repositář se čtyřmi vydáními balíčku integers | https://github.com/tisnik/integers |
20. Odkazy na Internetu
- Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go