Obsah
1. Ladění aplikací naprogramovaných v Go s využitím GNU Debuggeru a debuggeru Delve
3. Příprava aplikací napsaných v Go pro ladění v GNU Debuggeru
5. Spuštění programu, nastavení breakpointů a krokování
8. Informace o lokálních proměnných, zobrazení datových typů programovacího jazyka Go
10. Informace o zásobníkových rámcích a o vláknech
12. Spuštění debuggeru, načtení aplikace a nastavení breakpointů
13. Zobrazení obsahu datových typů programovacího jazyka Go
14. Zobrazení obsahu zásobníku
15. Demonstrační příklad využívající gorutiny
16. Základní informace o gorutinách
17. Demonstrační příklad používající kanály
18. Základní informace o kanálech
19. Repositář s demonstračními příklady
1. Ladění aplikací naprogramovaných v Go s využitím GNU Debuggeru a debuggeru Delve
Důležitou součástí vývoje aplikací je samozřejmě i jejich ladění. V případě programovacího jazyka Go je možné využít hned několika prostředků usnadňujících ladění. Kromě nástrojů určených pro měření a následnou analýzu různých metrik (sem spadá i standardní profiler, nástroj pro trasování programu při testování, popř. standardní balíček expvar, který si popíšeme příště) se samozřejmě jedná o i o debuggery. Využít je možné klasický GNU Debugger, ovšem s několika omezeními, které vyplývají z toho, že programovací jazyk Go má některé vlastnosti, s nimiž se v GNU Debuggeru původně nepočítalo (například goroutiny). Základní seznámení s možnostmi GNU Debuggeru je věnována první část článku. Ovšem kromě toho existuje i debugger určený přímo pro ekosystém programovacího jazyka Go. Tento debugger se jmenuje Delve a jeho popisem se budeme zabývat ve druhé části dnešního článku.
Kromě debuggerů používaných pro aplikace běžící v uživatelském prostoru samozřejmě existují i nástroje využívané pro ladění jádra, popř. pro ladění základních knihoven. Jak může vypadat použití jednotlivých nástrojů na celém „stacku“, tj. od trasování/ladění samotné uživatelské aplikace až přes řešení problémů přímo v jádře operačního systému, je naznačeno na následujícím schématu:
+----------+ | |..... gdb | aplikace | | |..... SystemTap +----------+ | | |...... ltrace | v +----------+ | |..... gdb | glibc | | |..... SystemTap +----------+ | | |...... strace | v +----------+ | |..... SystemTap | jádro | | |..... KGDB +----------+
Vidíme, že dnes popisovaný GNU Debugger je možné použít jak na úrovni ladění aplikace, tak i knihoven. Kromě toho ho lze využít i pro „pitvu“ těch nativních aplikací, které byly kvůli nějakému problému zabity jádrem systému a byl pro ně vygenerován takzvaný „core dump“.
2. Klasický GNU Debugger
Nejprve si popíšeme základní operace, které nám nabízí GNU Debugger při ladění aplikací vyvinutých v programovacím jazyku Go. GNU Debugger v současnosti oficiálně podporuje následující programovací jazyky:
# | Jazyk |
---|---|
1 | Ada |
2 | Assembly |
3 | C |
4 | C++ |
5 | D |
6 | Fortran |
7 | Go |
8 | Objective-C |
9 | OpenCL |
10 | Modula-2 |
11 | Pascal |
12 | Rust |
Nástroj GNU Debugger, který je taktéž někdy podle své spustitelné (binární) části pojmenováván gdb, primárně používá ke komunikaci s uživatelem příkazový řádek, ale alternativně lze použít i jednoduché TUI (textové uživatelské rozhraní) či protokol pro nepřímé ovládání debuggeru a v případě potřeby je možné k laděné aplikaci přidat relativně krátký „stub“ sloužící pro přímé ladění takové aplikace (touto nepochybně zajímavou problematikou se však dnes nebudeme zabývat). Většina často používaných příkazů zapisovaných na příkazový řádek má i svoji zkrácenou podobu (b=break, bt=backtrace, c=continue, f=frame) a navíc je možné používat klávesu [Tab] určenou pro automatické doplnění celého jména příkazu či jeho parametru (doplňování je kontextové). Pokud je správně nastavený terminál, bude fungovat i historie příkazového řádku, a to stejným způsobem, jaký známe ze shellu (BASH atd.). Alternativně je možné využít gdbtui s celoobrazovkovým výstupem a alespoň částečně se tak přiblížit možnostem debuggerů s plnohodnotným grafickým uživatelským rozhraním.
Práce s příkazovým řádkem GNU Debuggeru sice programátorům přináší velkou flexibilitu, ovšem je pochopitelné, že některým uživatelům příkazová řádka nemusí vyhovovat. To však – alespoň teoreticky – nemusí být nepřekonatelným problémem, protože již v úvodní kapitole jsme si řekli, že GDB je navržen takovým způsobem, aby se nad ním daly vytvářet různé nadstavby vybavené více či méně konformním textovým či grafickým uživatelským rozhraním. O nadstavbách vytvořených nad GNU Debuggerem jsem již napsal krátký seriál na „konkurenčním“ webu http://www.mojefedora.cz, takže si dnes o každé nadstavbě řekneme pouze základní informace (nejdůležitější informací je v době Googlu samozřejmě jméno nadstavby :-), zbytek se již dá dohledat na stránkách vývojářů toho kterého nástroje).
Nástroj nazvaný cgdb, o němž jsem se zmínil zde, je založený na knihovně curses, resp. ncurses, tudíž ho je možné využít v terminálu, na stroji připojeném přes SSH atd. Ve svém základním nastavení nástroj cgdb rozděluje okno terminálu (konzole) na dvě části. V horní části je zobrazen zdrojový kód laděné aplikace a v části dolní pak rozhraní samotného GNU Debuggeru. Mezi oběma částmi je možné se s využitím několika klávesových zkratek přepínat, přičemž je nutné poznamenat, že většinu složitějších příkazů je možné zadávat jen v rozhraní GNU Debuggeru. Horní část slouží zejména pro dobrou orientaci v laděném programu, pro zobrazení nastavených breakpointů (v základním nastavení je použita červená barva) a taktéž pro zobrazení místa, v němž se právě nachází laděný program (v základním nastavení je tento řádek zobrazen zeleně).
Obrázek 1: Ladění programu v cgdb. Na řádku 21 je nastaven breakpoint, proto je tento řádek zvýrazněn červeně. Řízení programu přešlo na řádek číslo 23 (zvýrazněno zeleně) a v dolní části si vývojář s využitím příkazu print vypsal obsah dvou lokálních proměnných.
O nástroji nazvaném Data Display Debugger, který je známý i pod svojí zkratkou DDD, taktéž vznikl článek na serveru mojefedora.cz, takže si zde pouze ve stručnosti řekněme, že Data Display Debugger je nadstavbou nad GNU Debuggerem, která nabízí uživatelům při ladění aplikací plnohodnotné grafické uživatelské rozhraní, jehož jednotlivé ovládací prvky a jejich chování sice mohou působit zastarale (což je způsobeno použitou GUI knihovnou), ve skutečnosti je však celé uživatelské rozhraní Data Display Debuggeru velmi flexibilní, což vynikne především při použití dvou a více monitorů (to je dnes pro vývojáře asi standardní konfigurace). Příkladem flexibility GUI jsou například „odtrhávací“ menu (tear off menu), které je možné velmi snadno změnit na nemodální dialogy s nabídkou příkazů. Data Display Debugger lze využít i pro komunikaci s dalšími debuggery, například s debuggerem jazyka Perl, debuggerem skriptů psaných v BASHi a v neposlední řadě taktéž pro ovládání pydb, což je jeden z debuggerů používaných vývojáři používajícími programovací jazyk Python.
Obrázek 2: Ukázka grafického uživatelského rozhraní programu Data Display Debugger. V horní části můžeme vidět okno se zdrojovým kódem, v prostřední části pak výpis odpovídajícího strojového kódu a spodní třetina GUI obsahuje klasický příkazový řádek GNU Debuggeru. K dispozici je i dialogové okno se základními a často používanými příkazy.
I o dalším nástroji pojmenovaném Nemiver již vyšel samostatný článek. Tento nástroj opět komunikuje s GNU Debuggerem, ovšem na rozdíl od DDD postaveného nad postarší GUI knihovnou je Nemiver primárně určený pro desktopové prostředí GNOME se všemi přednostmi a zápory, které to přináší. Nemiver tak uživatelům nabízí přehledné prostředí, které ovšem není tak flexibilní jako DDD a taktéž například možnosti zobrazení složitějších datových struktur (různých lineárně vázaných seznamů, stromů či obecnějších grafových struktur) jsou v Nemiveru omezené. Pokud ale někdo pouze potřebuje odkrokovat několik funkcí a neprovádět žádné složitější operace, může být tento nástroj pro takového uživatele dobrým řešením.
Obrázek 3: Ukázka grafického uživatelského rozhraní nástroje Nemiver při ladění uživatelské aplikace. V dolní části si povšimněte „oušek“ jednotlivých podoken.
3. Příprava aplikací napsaných v Go pro ladění v GNU Debuggeru
U aplikací naprogramovaných například v céčku je jediným požadavkem na bezproblémové použití GNU Debuggeru vypnutí optimalizací a přidání ladicích informací. Podobně je tomu i v případě, že budeme chtít ladit aplikace vytvořené v jazyku Go, navíc se ovšem ještě kvůli lepší kompatibilitě doporučuje vypnutí komprimace ladicích informací ve výsledném binárním souboru.
První pokusy s GNU Debuggerem učiníme při ladění a krokování následujícího prográmku, který po svém spuštění sečte dvě hodnoty a vypíše výsledek výpočtu na standardní výstup:
package main import "fmt" func main() { x := 10 y := 20 z := x + y fmt.Printf("%d + %d = %d\n", x, y, z) }
Tento program přeložíme, ovšem při samotném překladu explicitně nastavíme některé nestandardní parametry překladače i linkeru. Zejména se vypne inlining funkcí a automatické použití registrů pro některé proměnné. Taktéž se zakáže již zmíněná komprimace ladicích informací:
$ go build -ldflags=-compressdwarf=false -gcflags=all="-N -l" 01_add.go
Po prvním spuštění GNU Debuggeru se zobrazí varování, že nebylo možné nakonfigurovat pomocný modul používaný při ladění aplikací naprogramovaných v Go. Současně se zobrazí i přesný návod, jak tento problém napravit:
Obrázek 4: První spuštění GNU Debuggeru s informacemi o tom, že se nepodařilo inicializovat pomocný skript používaný při ladění Go aplikací.
Jakmile výše navržené nastavení provedeme, bude již nové spuštění GNU Debuggeru bezproblémové:
Obrázek 5: Načtení přeloženého programu do GNU Debuggeru.
4. Orientace v laděném kódu
V případě, že jsou do binárního souboru laděné aplikace přiloženy i ladicí symboly, lze v GNU Debuggeru relativně snadno pracovat přímo se zdrojovým kódem a využívat jména funkcí, jména proměnných, parametrů funkcí atd. Taktéž je možné prohlížet obsah datových struktur, polí, popř. i řezů, který bude správně interpretován. Nyní si ukažme některé příkazy, které využijete prakticky při každém ladění. Debugger přitom bude spuštěn a bude do něho načtena binární verze prvního příkladu:
$ gdb 01_add
Základním příkazem, který se může hodit například při nastavování breakpointů, je příkaz info functions, který vypíše jak všechny funkce z aplikace, tak i přímo či nepřímo volané funkce (pro zápis tohoto příkazu použijte klávesu [Tab] pro kontextové doplňování):
Obrázek 6: Zobrazení seznamu všech funkcí nalezených v načteném binárním programu a/nebo binární knihovně po zadání příkazu list functions.
Dalším užitečným příkazem je příkaz list, který ve svém výchozím nastavení vypíše deset řádků zdrojového kódu. Opakováním příkazu (či pouhým stlačením klávesy Enter, což má stejný význam, jako explicitní opakování posledního příkazu) se zobrazí dalších deset řádků atd.:
(gdb) list 1 package main 2 3 import "fmt" 4 5 func main() { 6 x := 10 7 y := 20 8 9 z := x + y 10
K příkazu list je možné explicitně přidat i číslo prvního a posledního vypisovaného řádku, což je výhodné v případě, že z nějakého chybového hlášení víte, na kterém řádku k chybě došlo.
(gdb) list 5,10 5 func main() { 6 x := 10 7 y := 20 8 9 z := x + y 10
Užitečnější je však použití příkazu list společně se jménem funkce, protože nemusíte složitě zjišťovat, na jakém řádku je hledaná funkce zapsána (ani v jakém je souboru):
(gdb) list main.main 1 package main 2 3 import "fmt" 4 5 func main() { 6 x := 10 7 y := 20 8 9 z := x + y 10
Pokud chcete jméno funkce vybrat ze seznamu, stačí napsat jen příkaz list, mezeru a potom stlačit klávesu [Tab].
Užitečné mohou být i další varianty příkazu info:
(gdb) info info address -- Describe where symbol SYM is stored info all-registers -- List of all registers and their contents info args -- Argument variables of current stack frame info auto-load -- Print current status of auto-loaded files info auto-load-scripts -- Print the list of automatically loaded Python scripts info auxv -- Display the inferior's auxiliary vector ... ... ... info warranty -- Various kinds of warranty you do not have info watchpoints -- Status of specified watchpoints (all watchpoints if no argument) info win -- List of all displayed windows Type "help info" followed by info subcommand name for full documentation. Type "apropos word" to search for commands related to "word". Command name abbreviations are allowed if unambiguous.
Například:
(gdb) info line Line 5 of "/home/tester/go-root/article_25/01_add.go" starts at address 0x49dc40 <main.main> and ends at 0x49dc58 <main.main+24>.
5. Spuštění programu, nastavení breakpointů a krokování
Nyní se podíváme na způsob spuštění laděné aplikace přímo v GNU Debuggeru. To je ve skutečnosti velmi jednoduché a přímočaré, protože postačuje zadat příkaz run či jen r:
(gdb) r Starting program: /home/tester/temp/go-root/article_25/01_add 10 + 20 = 30 [Inferior 1 (process 4244) exited normally]
Na libovolnou funkci, řádek či dokonce jednotlivou strojovou instrukci je možné zaregistrovat breakpoint. Pokud se běh programu dostane na breakpoint, je jeho běh přerušen a řízení se vrátí zpět uživateli do debuggeru. Nejjednodušeji se nastavuje breakpoint na vstupním bodě nějaké (libovolně zvolené) funkce. V tomto případě postačuje zadat příkaz break se jménem funkce:
Obrázek 7: Nastavení breakpointu na první příkaz ve funkcí main. Plné jméno této funkce musí obsahovat i balíček, tedy main.main.
Pokud nyní program znovu spustíme, zastaví se na právě nastaveném breakpointu:
Obrázek 8: Po spuštění programu příkazem r nebo run se jeho běh zastaví na breakpointu, tj. na prvním příkazu ve funkci main.
Nyní máme možnost pokračovat v běhu (c/continue), ale zajímavější je použít příkaz n/next, který vykoná pouze jediný programový řádek a posléze se běh programu opět zastaví. Vykonávaný řádek se přitom vždy vypíše (pokud tedy nemáme zobrazeno TUI, potom se GNU Debugger chová odlišně):
Obrázek 9: Krokování jednotlivými příkazy pomocí příkazu n nebo next.
O tom, že GNU Debugger není žádné ořezávátko, možná svědčí i to, že se v průběhu ladění může použít mj. i příkaz print akceptující různé typy výrazů, lokální i globální proměnné, formátování atd.:
Obrázek 10: Po vykonání posledního příkazu ve funkci main se program pochopitelně ukončí.
6. Využití TUI GNU Debuggeru
Pro úplnost se ještě podívejme na to, jak vypadá TUI (textové uživatelské rozhraní) zabudované do GNU Debuggeru, přesněji řečeno do jeho novějších verzí. TUI je nutné povolit, a to buď spuštěním GNU Debuggeru nikoli příkazem gdb, ale příkazem gdbtui, popř. kdykoli při běhu GNU Debuggeru příkazem:
(gdb) tui enable
Obrázek 11: GNU Debugger po zobrazení textového uživatelského rozhraní ve chvíli, kdy je nastaven breakpoint na vstupní bod (přesněji řečeno na první příkaz) ve funkci main. Na levém okraji se zobrazují jak breakpointy, tak i ukazatel na právě prováděný či krokovaný příkaz.
V základním nastavení je terminál rozdělen do dvou oken – první okno obsahuje zdrojový kód, druhé pak klasické rozhraní příkazového řádku. Ve skutečnosti je však možné zobrazit i další okna, například speciální okno s registry atd. V okně se zdrojovým kódem se navíc zobrazují breakpointy a další důležité informace, takže „režim TUI“ může být pro mnohé vývojáře velmi užitečný (dokonce si dovolím říct, že je časově výhodnější se naučit pracovat v tomto režimu, než řešit problémy s různými GUI nadstavbami nad GNU Debuggerem).
Obrázek 12: Krokování programu (příkaz n/next) při zobrazeném TUI. Zatímco znak breakpointu zůstal (pochopitelně) na svém místě, ukazatel na právě prováděný příkaz se přesunul.
(gdb) apropos tui set tui -- TUI configuration variables set tui active-border-mode -- Set the attribute mode to use for the active TUI window border set tui border-kind -- Set the kind of border for TUI windows set tui border-mode -- Set the attribute mode to use for the TUI window borders show tui -- TUI configuration variables show tui active-border-mode -- Show the attribute mode to use for the active TUI window border show tui border-kind -- Show the kind of border for TUI windows show tui border-mode -- Show the attribute mode to use for the TUI window borders tui -- Text User Interface commands tui reg -- TUI commands to control the register window
7. Příkaz display
Již v předchozích kapitolách jsme si řekli, že libovolnou proměnnou (či dokonce výsledek nějakého složitějšího výrazu) je možné zobrazit příkazem print. Velmi často, zejména při ladění různých programových smyček, je však zapotřebí neustále zjišťovat hodnoty několika proměnných, a to v každém sledovaném kroku. V tomto případě je pochopitelně opakované použití příkazu print nepříjemné, ovšem GNU Debugger obsahuje ještě jeden příkaz: display:
(gdb) help display Print value of expression EXP each time the program stops. /FMT may be used before EXP as in the "print" command. /FMT "i" or "s" or including a size-letter is allowed, as in the "x" command, and then EXP is used to get the address to examine and examining is done as in the "x" command. With no argument, display all currently requested auto-display expressions. Use "undisplay" to cancel display requests previously made.
Tímto příkazem je tedy možné „zaregistrovat“ ty výrazy, které se mají neustále vyhodnocovat, a to v každém kroku ladění. Podívejme se na praktické použití tohoto velmi užitečného příkazu:
Obrázek 13: Při krokování funkcí main.main budeme sledovat obsah lokálních proměnných x, y a z. Povšimněte si, že ihned po vstupu do funkce mají tyto proměnné nedefinovanou hodnotu.
Obrázek 14: Třikrát jsme spustili příkaz next, takže se provedly první tři řádky s příkazy ve funkci main.main. Před provedením příkazu na řádku 11 jsou všechny sledované proměnné inicializované a mají očekávané hodnoty.
8. Informace o lokálních proměnných, zobrazení datových typů programovacího jazyka Go
Nyní si ukážeme, jak dobře (či špatně) dokáže GNU Debugger sledovat hodnoty lokálních proměnných ve chvíli, kdy jsou použity datové typy specifické pro programovací jazyk Go. Začneme aplikací, v níž se používá jedno pole a několik řezů (slice):
package main import "fmt" func main() { var a1 [20]int for i := 0; i < len(a1); i++ { a1[i] = i + 1 } var slice1 []int = a1[:] var slice2 []int = a1[5:15] slice3 := slice2[5:] fmt.Println(a1) fmt.Println(slice1) fmt.Println(slice2) fmt.Println(slice3) }
Překlad aplikace:
$ go build -ldflags=-compressdwarf=false -gcflags=all="-N -l" 02_arrays_slices.go
Spuštění debuggeru:
$ gdb 02_arrays_slices
Nyní již můžeme sledovat chování debuggeru při krokování jednotlivými příkazy ve funkci main.main:
Obrázek 15: Načtení aplikace do GNU Debuggeru a zobrazení jejího zdrojového kódu.
Obrázek 16: Po nastavení breakpointu a spuštění programu se dostaneme před první příkaz funkce main.main.
Obrázek 17: Příkazem info locals zobrazíme informaci o všech lokálních proměnných funkce, ve které se nacházíme.
Obrázek 18: Příkazem n přejdeme až na řádek, v němž jsou všechny lokální proměnné inicializovány.
Obrázek 19: Zobrazení obsahu řezů (slices).
Obrázek 20: Pseudofunkcemi $cap() a $len() můžeme získat informace o kapacitě řezu a o jeho délce (což jsou dvě hodnoty, které se od sebe mohou lišit).
9. Zobrazení prvků struktur
Podobným způsobem si můžeme vyzkoušet, jak dobře dokáže GNU Debugger zobrazit informace o strukturách (záznamech). Pro toto otestování použijeme zdrojový kód s novým datovým typem představujícím uživatelsky definovanou datovou strukturu pojmenovanou jednoduše User:
package main import "fmt" type User struct { id uint32 name string surname string } func main() { user1 := User{ id: 1, name: "Linus", surname: "Torvalds"} fmt.Println(user1) user1.id = 2 user1.name = "Steve" user1.surname = "Ballmer" fmt.Println(user1) }
Opět si ukažme chování GNU Debuggeru:
Obrázek 21: Načtení aplikace do GNU Debuggeru a zobrazení jejího zdrojového kódu. Nastavení breakpointu a zobrazení informace o datovém typu User.
Použili jsme zde nový příkaz whatis:
(gdb) help whatis Print data type of expression EXP. Only one level of typedefs is unrolled. See also "ptype".
Obrázek 22: Zajímavá (ale nijak nebezpečná) situace, která nastala ve chvíli, kdy není obsah datové struktury inicializován, tj. její prvky mohou obsahovat jakoukoli hodnotu.
Obrázek 23: I samotná inicializace datové struktury je krokovatelná; v tomto případě se skládá ze třech kroků.
10. Informace o zásobníkových rámcích a o vláknech
Při ladění se velmi často dostaneme do situace, kdy je nutné sledovat obsah zásobníkových rámců (stack frame). V GNU Debuggeru se pro tento účel používá příkaz info frame, který je použitelný i při ladění aplikací naprogramovaných v jazyku Go (i když tento jazyk používá jiný formát rámců, mj. i kvůli podpoře gorutin atd.). Tuto funkcionalitu otestujeme na příkladu, v němž se rekurzivně počítá hodnota faktoriálu:
package main import "fmt" func factorial(x uint) uint { if x == 0 { return 1 } else { return x * factorial(x-1) } } func main() { fmt.Println(factorial(4)) }
Breakpoint přitom nastavíme na příkaz return 1, který je umístěn v podmínce zaručující, že již došlo k celé zavinovací (winding) fázi rekurze:
Obrázek 24: Načtení laděného programu a nastavení breakpointu.
Obrázek 25: Spuštění programu (ten se zastaví na breakpointu) a vytištění obsahu aktuálního zásobníkového rámce příkazem info frame.
Obrázek 26: Zobrazit si můžeme i takzvaný backtrace, z něhož lze vyčíst historii zavinovací fáze rekurzivního výpočtu.
Obrázek 27: Získat je možné i seznam běžících gorutin, popř. fyzických vláken. Zásobníkové rámce se poté vypíšou pro vybrané vlákno.
11. Debugger Delve
Ve druhé části dnešního článku se seznámíme s některými základními možnostmi, které jsou nabízeny debuggerem Delve. Na rozdíl od GNU Debuggeru, který podporuje mnoho programovacích jazyků i formátů souborů/knihoven, je Delve určen primárně pro použití těmi vývojáři, kteří používají programovací jazyk Go. Delve je přitom pro Go programátory doporučovaným primárním debuggerem, což mj. znamená, že práce na vylepšení kooperace mezi Go a GNU Debuggerem mají relativně nízkou prioritu. I to může být jeden z důvodů, proč je doporučován přechod na tento debugger, i když je nutné již na úvod poznamenat, že ne všechny funkce, které jsou dostupné v GNU Debuggeru nalezneme i v nástroji Delve.
Obrázek 28: Přepínače, s nimiž je možné spustit debugger Delve.
Debugger Delve se nainstaluje podobně, jako jakýkoli jiný balíček připravený pro programovací jazyk Go:
$ go get -u github.com/go-delve/delve/cmd/dlv
Po instalaci se pro jistotu přesvědčte, že v proměnné prostředí PATH je nastavena i cesta do adresáře ~/go/bin/.
Obrázek 29: Část seznamu všech příkazů debuggeru Delve.
12. Spuštění debuggeru, načtení aplikace a nastavení breakpointů
Debugger Delve se spouští příkazem dlv. Při spuštění je nutné specifikovat, jaká operace se má provést. Pro ladění a krokování aplikací se použije operace debug a v tomto případě je debuggeru nutné předat i jméno balíčku, popř. jméno souboru se zdrojovým kódem (samotný překlad nemusíme provést):
$ dlv debug 01_add.go
Breakpoint se nastavuje stejným příkazem b, jako v GNU Debuggeru:
(dlv) b man.main
Následně se může program spustit příkazem c (continue).
Obrázek 30: Spuštění debuggeru, inicializace laděné aplikace, nastavení breakpointu a doskok na breakpoint.
Příkazy n a locals pracují podobně, jako v GNU Debuggeru:
Obrázek 31: Výpis obsahu lokálních proměnných, přičemž pouze dvě z nich jsou v daný okamžik inicializovány.
Obrázek 32: Krokovat je možné i kódem, který se spouští při opouštění aplikace.
13. Zobrazení obsahu datových typů programovacího jazyka Go
Debugger Delve pochopitelně dokáže pracovat s hodnotami libovolného datového typu programovacího jazyka Go. Pro otestování těchto funkcí použijeme ty stejné demonstrační příklady, jako tomu bylo u GNU Debuggeru:
Obrázek 33: Zobrazení obsahu (prvků) pole a řezu. Povšimněte si, že v případě řezu se zobrazí jak kapacita, tak i aktuální délka.
Obrázek 34: Zobrazení obsahu uživatelsky definované datové struktury (záznamu).
Další možnosti jsou popsány v nápovědě:
(dlv) help print Evaluate an expression. [goroutine ] [frame ] print See $GOPATH/src/github.com/go-delve/delve/Documentation/cli/expr.md for a description of supported expressions.
(dlv) help locals Print local variables. [goroutine <n>] [frame <m>] locals [-v] [<regex>] The name of variables that are shadowed in the current scope will be shown in parenthesis. If regex is specified only local variables with a name matching it will be returned. If -v is specified more information about each local variable will be shown.
14. Zobrazení obsahu zásobníku
I v Delve je pochopitelně možné zobrazit obsah zásobníku, resp. přesněji řečeno obsah jednotlivých zásobníkových rámců. Tuto funkcionalitu si opět vyzkoušíme na demonstračním příkladu, v němž je implementován rekurzivní výpočet faktoriálu. Breakpoint nastavíme na příkaz return 1, jenž je zavolaný při ukončení zavinovací fáze rekurze:
Obrázek 35: Zastavení běhu programu (resp. aktuální gorutiny) na řádku return 1.
Následně je možné použít příkaz stack pro zobrazení historie volání funkcí:
(dlv) help stack Print stack trace. [goroutine <n>] [frame <m>] stack [<depth>] [-full] [-offsets] [-defer] [-a <n>] [-adepth <depth>] -full every stackframe is decorated with the value of its local variables and arguments. -offsets prints frame offset of each frame. -defer prints deferred function call stack for each frame. -a <n> prints stacktrace of n ancestors of the selected goroutine (target process must have tracebackancestors enabled) -adepth <depth> configures depth of ancestor stacktrace
Obrázek 36: Zobrazení obsahu zásobníkových rámců.
Podrobnější informace poskytne příkaz stack -full:
(dlv) stack -full 0 0x00000000004a0b70 in main.factorial at ./04_factorial.go:7 x = 0 ~r1 = 0 1 0x00000000004a0b94 in main.factorial at ./04_factorial.go:9 x = 1 ~r1 = 0 2 0x00000000004a0b94 in main.factorial at ./04_factorial.go:9 x = 2 ~r1 = 0 3 0x00000000004a0b94 in main.factorial at ./04_factorial.go:9 x = 3 ~r1 = 0 4 0x00000000004a0b94 in main.factorial at ./04_factorial.go:9 x = 4 ~r1 = 0 5 0x00000000004a0bee in main.main at ./04_factorial.go:14 6 0x000000000042da0f in runtime.main at /opt/go/src/runtime/proc.go:200 needUnlock = false g = (*runtime.g)(0xc000000180) fn = (unreadable empty OP stack) 7 0x0000000000457a81 in runtime.goexit at /opt/go/src/runtime/asm_amd64.s:1337
15. Demonstrační příklad využívající gorutiny
Pro zjištění informací o gorutinách použijeme jiný demonstrační příklad, který po svém spuštění inicializuje a spustí tři další gorutiny, jenž budou pracovat současně:
package main import ( "fmt" "time" ) func print_chars() { for ch := 'a'; ch <= 'z'; ch++ { fmt.Printf("%c", ch) time.Sleep(200 * time.Millisecond) } } func print_dots() { for i := 0; i < 30; i++ { fmt.Print(".") time.Sleep(200 * time.Millisecond) } } func print_spaces() { for i := 0; i < 60; i++ { fmt.Print(" ") time.Sleep(110 * time.Millisecond) } } func main() { fmt.Println("main begin") go print_chars() go print_spaces() go print_dots() time.Sleep(6 * time.Second) fmt.Println("main end") }
16. Základní informace o gorutinách
Po nastavení breakpointu na řádek:
time.Sleep(6 * time.Second)
si můžeme zobrazit všechny gorutiny, a to příkazem goroutines. Příkaz gorutine (bez „s“ na konci) slouží pro zobrazení podrobnějších informací o aktuálně sledované gorutině:
Obrázek 37: Informace o aktuálně sledované gorutině i seznam všech dalších gorutin.
Další informace samozřejmě opět poskytne nápověda:
(dlv) help goroutine Shows or changes current goroutine ... ... ...
a:
(dlv) help goroutines List program goroutines. goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)|-s (start location)] [ -t (stack trace)] Print out info for every goroutine. The flag controls what information is shown along with each goroutine: -u displays location of topmost stackframe in user code -r displays location of topmost stackframe (including frames inside private runtime functions) -g displays location of go instruction that created the goroutine -s displays location of the start function -t displays stack trace of goroutine If no flag is specified the default is -u.
17. Demonstrační příklad používající kanály
Kanály slouží mj. i pro předávání dat mezi gorutinami. Z pohledu debuggeru Delve se jedná o běžný datový typ (i když interně dosti komplikovaný), jehož obsah lze snadno zobrazit. To si ověříme na následujícím příkladu:
package main import "fmt" func message(id int, channel chan int) { fmt.Printf("gorutina %d\n", id) channel <- 1 } func main() { channel := make(chan int) fmt.Println("main begin") go message(1, channel) fmt.Println("waiting...") code, status := <-channel fmt.Printf("received code: %d and status: %t\n", code, status) fmt.Println("main end") }
18. Základní informace o kanálech
Informace o kanálu, resp. přesněji řečeno o obsahu proměnné typu kanál, se zobrazí příkazem print nebo zkráceně jen p:
Obrázek 38: Zobrazení informací o kanálu po jeho inicializaci v debuggeru.
Obrázek 39: Druhá obrazovka naznačující, jak je kanál ve skutečnosti složitou datovou strukturou.
Obrázek 40: V této chvíli běží v aplikaci dvě gorutiny.
Podrobnější informace o frontě vytvořené pro předávání zpráv přes kanál:
(dlv) p channel.sendq waitq<int> { first: *sudog<int> { g: *(*runtime.g)(0xc000001080), isSelect: false, next: *runtime.sudog nil, prev: *runtime.sudog nil, elem: *1, acquiretime: 0, releasetime: 0, ticket: 0, parent: *runtime.sudog nil, waitlink: *runtime.sudog nil, waittail: *runtime.sudog nil, c: *(*runtime.hchan)(0xc000080060),}, last: *sudog<int> { g: *(*runtime.g)(0xc000001080), isSelect: false, next: *runtime.sudog nil, prev: *runtime.sudog nil, elem: *1, acquiretime: 0, releasetime: 0, ticket: 0, parent: *runtime.sudog nil, waitlink: *runtime.sudog nil, waittail: *runtime.sudog nil, c: *(*runtime.hchan)(0xc000080060),},}
Obrázek 41: Přepnutí na jinou gorutinu, která se bude sledovat.
19. Repositář s demonstračními příklady
Zdrojové kódy všech šesti dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně dva megabajty), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
# | Soubor | Popis | Cesta |
---|---|---|---|
1 | 01_add.go | jednoduchý program, který sečte dvojici celočíselných hodnot | https://github.com/tisnik/go-root/blob/master/article25/01_add.go |
2 | 02_arrays_slices.go | základní operace s poli a s řezy | https://github.com/tisnik/go-root/blob/master/article25/02_arrays_slices.go |
3 | 03_structs.go | práce se strukturami (záznamy) | https://github.com/tisnik/go-root/blob/master/article25/03_structs.go |
4 | 04_factorial.go | rekurzivní výpočet faktoriálu | https://github.com/tisnik/go-root/blob/master/article25/04_factorial.go |
5 | 05_goroutines.go | spuštění dvou gorutin | https://github.com/tisnik/go-root/blob/master/article25/05_goroutines.go |
6 | 06_channels.go | gorutiny a kanály | https://github.com/tisnik/go-root/blob/master/article25/06_channels.go |
20. Odkazy na Internetu
- 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 - 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