Obsah
1. Kooperace mezi kódem psaným v Go a C: cgo
3. Speciální balíček nazvaný „C“
4. Volání funkcí deklarovaných v C z kódu psaného v Go
6. Převody celočíselných datových typů mezi Go a C
7. Přilinkování další nativní knihovny
9. Upravený příklad pro tisk řetězce na standardní výstup
10. Použití deklarace defer při uvolňování paměti
11. Uvolnění paměti před jejím použitím
12. Dvojí zavolání funkce C.free()
13. Nepřímé čtení proměnné errno
14. Deklarace céčkovské funkce v komentáři
15. Práce s řetězci alokovanými funkcemi jazyka C
16. Prohlédnutí kódu generovaného překladačem jazyka Go
17. Repositář s demonstračními příklady
1. Kooperace mezi kódem psaným v Go a C: cgo
Prozatím jsme se v seriálu o programovacím jazyce Go zabývali především samotným programovacím jazykem Go, jeho knihovnami a dostupnými pomocnými nástroji. V předchozích dvou částech [1] [2] jsme si navíc připomenuli některé poměrně zásadní rozdíly mezi jazyky C a Go, které mohou zajímat především ty programátory, kteří na Go přechází právě z jazyka C. A dnes na toto téma nepřímo navážeme, protože si na několika demonstračních příkladech ukážeme kooperaci mezi programovým kódem napsaným v Go na jedné straně a kódem vyvinutým v jazyku C na straně druhé.
Již v základní sadě nástrojů programovacího jazyka Go mají vývojáři k dispozici prakticky všechny utility a knihovny potřebné proto, aby se z kódu vyvíjeného v jazyce Go mohly volat funkce naprogramované v C a uložené například v linkovaných knihovnách. Díky tomu je kooperace mezi Go a C relativně snadná, resp. přesněji řečeno nám existence potřebných nástrojů umožní se soustředit na složitější a pro běh aplikací i podstatnější problémy – zejména jak správně konvertovat parametry volaných funkcí, jak zpracovat jejich návratové hodnoty popř. chybové hodnoty a především pak, jak korektně pracovat s operační pamětí. Při kooperaci mezi Go a C totiž zásadní problém spočívá v tom, že v jazyce Go se alokovaná paměť uvolňuje automaticky správcem paměti (garbage collector – GC), zatímco v jazyce C se pochopitelně o alokaci i dealokaci paměti musí postarat sám programátor.
2. Speciální balíček nazvaný „C“
Při práci s funkcemi vytvořenými v programovacím jazyku C nebo i s celými knihovnami musíme být schopni tyto funkce nějakým způsobem volat z kódu napsaného v jazyku Go. Připomeňme si, že v Go platí následující pravidla pro volání funkcí (tato pravidla jsem zjednodušil a poněkud zkrátil):
- Funkce deklarované v rámci toho samého balíčku se volají přímým zápisem jejich jména. Přitom nezáleží na tom, zda je první písmeno v názvu funkce velké či malé. Tatáž pravidla platí i pro metody, akorát je u nich nutné uvést i jejích příjemce (receiver).
- Funkce deklarované v jiném balíčku se volají zápisemjméno_balíčku.JménoFunkce, přičemž jméno funkce musí začínat velkým písmenem. Pokud jméno funkce začíná písmenem malým, je funkce považována za privátní v rámci svého balíčku (kde je deklarována) a nebude ji možné z jiného balíčku přímo zavolat. Tímto způsobem se v Go řídí viditelnost funkcí a popř. i povolují či zakazují některé optimalizace prováděné překladačem.
- Balíčky s volanými funkcemi musí být explicitně importovány a v rámci importu je možné zadat i alias jména balíčku. Platí to i naopak – importovat je možné pouze ty balíčky, které jsou skutečně použity, ovšem s výjimkou dále zmíněného pseudobalíčku „C“.
V programovacím jazyku C však platí dosti odlišná pravidla. Zejména se zde nepoužívá koncept balíčků, ale namísto toho bývá (podle nastavení projektu) každý zdrojový soubor samostatně překládanou jednotkou, v níž lze deklarovat, které funkce mají být viditelné (exportované) z jiných modulů a které nikoli (static, ovšem toto klíčové slovo má více významů). Navíc zde neexistuje pravidlo, že se viditelnost funkcí určuje podle prvního písmene v jejich názvu.
Aby bylo možné i ze zdrojového kódu napsaného v Go volat céčkovské funkce, je překladačem jazyka Go podporován speciální balíček (spíše pseudobalíček) nazvaný „C“, jehož vlastnosti a chování jsou odlišné od standardních balíčků programovacího jazyka Go. S podrobnějšími informacemi o tomto pseudobalíčku se seznámíme v navazujících kapitolách.
3. Speciální balíček nazvaný „C“
Podívejme se nyní na základní vlastnost pseudobalíčku „C“. Tento balíček můžeme importovat (syntaxe je shodná s běžnými balíčky), a to dokonce bez toho, aby byl vůbec ve zdrojovém kódu reálně použit. To znamená, že následující zdrojový kód je zcela korektní a může být bez chyb přeložen překladačem jazyka Go:
package main import "C" func main() { }
Tato výjimka ovšem platí jen a pouze pro pseudobalíček „C“. Pokud se totiž pokusíme naimportovat běžný balíček jazyka Go, který nakonec nepoužijeme, vypíše překladač chybu:
package main import "fmt" func main() { }
Při pokusu o překlad se (správně) detekuje, že se importuje baliček, který není v kódu použit:
# command-line-arguments ./02_import_fmt.go:3:8: imported and not used: "fmt"
4. Volání funkcí deklarovaných v C z kódu psaného v Go
Funkce, které byly vytvořené v céčku popř. funkce uložené v některé céčkové (nativní) knihovně, se v programovacím jazyce Go volají následujícím způsobem:
C.jméno_funkce(parametry_funkce)
Další z odlišností mezi pseudobalíčkem „C“ a ostatními balíčky spočívá v tom, že z balíčku „C“ je možné volat i ty funkce, které začínají malým písmenem (což jsou prakticky všechny funkce ze standardní knihovny). Teoreticky se tedy můžeme pokusit zavolat funkci puts() ze standardní céčkové knihovny (viz též man 3 puts):
package main import "C" func main() { C.puts("Hello world!") }
Pokus o překlad se ovšem v tomto případě nezdaří, protože překladač nedokáže zjistit žádné podrobnější informace o volané funkci puts() (počet a typ parametrů atd.):
# command-line-arguments ./03_missing_include.go:6:2: could not determine kind of name for C.puts
Stojíme tedy před tímto problémem: máme zavolat funkci deklarovanou mimo samotný jazyk Go o které tedy překladač nemá k dispozici žádné podrobnější informace. Na tomto místě je nutné použít poněkud špinavý trik – vložit příkaz céčkového preprocesoru #include do poznámky umístěné před příkaz pro import pseudobalíčku „C“:
package main // #include <stdio.h> import "C" func main() { C.puts("Hello world!") }
5. Konverze řetězce z Go do C
Nyní již překladač programovacího jazyka Go volanou funkci správně rozpozná (a zná i její parametry), ovšem při pokusu o překlad vypíše odlišnou chybu, která se týká toho, že se snažíme zkombinovat řetězec deklarovaný v jazyce Go s funkcí akceptující céčkovský řetězec (ukončený nulou):
# command-line-arguments ./04_puts_go_string.go:7:16: cannot use "Hello world!" (type string) as type *_Ctype_char in argument to _Cfunc_puts
Řetězce v jazyce Go se v mnoha ohledech odlišují od céčkovských řetězců; nejedná se o stejný datový typ. Musíme tedy být schopni provést převod mezi neměnným řetězcem v jazyce Go a nulou ukončeným řetězcem jazyka C. Pro tuto konverzi lze použít funkci nazvanou CString, která je deklarovaná v rámci pseudobalíčku „C“:
cs := C.CString("Hello world!")
Upravený program, který po svém spuštění vypíše na standardní výstup řetězec „Hello world!“ tedy může vypadat takto:
package main // #include <stdio.h> import "C" func main() { cs := C.CString("Hello world!") C.puts(cs) }
Tento program je již přeložitelný a spustitelný:
Hello world!
6. Převody celočíselných datových typů mezi Go a C
Vyzkoušejme si nyní zavolat odlišnou céčkovskou funkci, konkrétně funkci nazvanou abs (viz též man 3 abs). Tato funkce akceptuje jeden parametr typu int a vrací taktéž hodnotu typu int. I zde musíme provést přetypování (int v Go na int v C, což pro překladač nejsou shodné typy). Konkrétně se převod Go int → C int provede s využitím funkce C.int(), opět patřící do pseudobalíčku „C“:
y := C.abs(C.int(x))
Výsledek céčkovské funkce abs můžeme použít přímo (alespoň v některých případech), a to díky automatickému odvození typu lokální proměnné y:
package main // #include <stdlib.h> import "C" import "fmt" func main() { x := -10 y := C.abs(C.int(x)) fmt.Printf("%v\n", y) }
Tento příklad po svém překladu a spuštění správně vypíše hodnotu 10:
10
Pokud ovšem budeme chtít použít výsledek (návratovou hodnotu) céčkovské funkce abs v jazyce Go, je výhodnější provést explicitní převod vrácené hodnoty na typ int. To lze provést například takto:
var y int = int(C.abs(C.int(x)))
Upravený zdrojový kód demonstračního příkladu vypadá následovně:
package main // #include <stdlib.h> import "C" import "fmt" func main() { x := -10 var y int = int(C.abs(C.int(x))) fmt.Printf("%v\n", y) }
I tento demonstrační příklad po svém překladu a spuštění správně vypíše hodnotu 10:
10
7. Přilinkování další nativní knihovny
Nyní již víme, jakým způsobem je možné volat funkce ze základní knihovny programovacího jazyka C (stdlib, stdio, string atd.). Vyzkoušejme si tedy poněkud odlišný příklad, konkrétně volání funkce sinf() z knihovny math (viz též man 3 sinf). Tato funkce akceptuje parametr typu float, který snadno získáme konverzní funkcí C.float(). Výsledek budeme konvertovat zpět standardní konverzní funkcí float32:
y := float32(C.sinf(C.float(x)))
První verze příkladu by tedy mohla vypadat následovně:
package main // #include <math.h> import "C" import "fmt" func main() { x := 3.1415927 / 6.0 y := float32(C.sinf(C.float(x))) fmt.Printf("%v\n", y) }
Pokud se předchozí příklad pokusíme přeložit, vypíše se chybové hlášení informující o tom, že funkce sinf nebyla nalezena, a to konkrétně linkerem (to tedy znamená, že překladač neměl s voláním této funkce problémy, ovšem linker neví, kde se tato funkce nachází):
# command-line-arguments /tmp/ramdisk/go-build217505370/b001/_x002.o: In function `_cgo_15d71de7baa2_Cfunc_sinf': /tmp/go-build/cgo-gcc-prolog:45: undefined reference to `sinf' collect2: error: ld returned 1 exit status
Podobné chybové hlášení by se vypsalo i při pokusu o překlad a slinkování běžného programu psaného v jazyce C, který by funkci sinf() volal. Důvod je jednoduchý – linkeru musíme oznámit, že má při sestavování výsledného binárního souboru použít i knihovnu m, která je na disku uložena v souboru libm.verze.so. V případě programovacího jazyka C je to jednoduché, protože máme přístup k příkazovému řádku, z něhož voláme cpp, cc a ld (popř. gcc), ovšem pokud budeme chtít knihovnu m použít i z Go, musíme parametry předávané linkeru přímo vložit do poznámky před import pseudobalíčku „C“:
// #cgo LDFLAGS: -lm
Upravený zdrojový kód bude vypadat následovně:
package main // #include <math.h> // #cgo LDFLAGS: -lm import "C" import "fmt" func main() { x := 3.1415927 / 6.0 y := float32(C.sinf(C.float(x))) fmt.Printf("%v\n", y) }
Nyní je již možné program přeložit i spustit:
0.5
8. Manuální uvolňování paměti
Dalším problémem, který je nutné vyřešit, je manuální uvolňování paměti. Týká se to především céčkových řetězců popř. céčkových polí vzniklých konverzí z řetězců/polí napsaných v programovacím jazyku Go.
Podívejme se na následující příklad, v němž se v nekonečné smyčce vypisuje zpráva na standardní výstup. Zpráva je získána konverzí původního řetězce v Go do nulou ukončeného céčkového řetězce. Tento řetězec není z paměti uvolněn, a to ani automaticky (leží mimo dosah GC) ani manuálně:
package main // #include <stdio.h> import "C" func main() { for { cs := C.CString("Hello world!") C.puts(cs) } }
Příklad je vhodné spustit tak, aby se zprávy zahazovaly (je to rychlejší, než jejích zobrazení na terminálu):
$ go run 10_oom.go < /dev/null
S využitím nástroje top se lze snadno přesvědčit, že paměť alokovaná novým procesem bude neustále růst; na konci většinou proces ukončí OOM killer (podle nastavení systému).
Pokud ovšem program upravíme takovým způsobem, že se řetězec bude uvolňovat, bude paměť alokovaná procesem prakticky stále konstantní:
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func main() { for { cs := C.CString("Hello world!") C.puts(cs) C.free(unsafe.Pointer(cs)) } }
9. Upravený příklad pro tisk řetězce na standardní výstup
Demonstrační příklad, který jsme si uvedli v páté kapitole, je tedy vhodné upravit takovým způsobem, aby se céčkový řetězec po použití funkcí puts() explicitně uvolnil z paměti:
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func main() { cs := C.CString("Hello world!") C.puts(cs) C.free(unsafe.Pointer(cs)) }
Výsledek bude shodný s předchozím příkladem:
Hello world!
10. Použití deklarace defer při uvolňování paměti
Jednou z velmi dobrých vlastností programovacího jazyka Go je deklarace defer, která nám umožňuje specifikovat programový kód, který se provede při návratu z aktuálně prováděné funkce. Nic nám samozřejmě nebrání použít defer i pro uvolnění céčkového řetězce (či jiné céčkové paměťové struktury) z operační paměti. Navíc bude zaručeno, že se funkce free() zavolá ve všech větvích funkce (pokud má funkce více výstupních bodů) a navíc že se nezavolá vícekrát (například omylem):
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func main() { cs := C.CString("Hello world!") defer C.free(unsafe.Pointer(cs)) C.puts(cs) }
Výsledek běhu tohoto příkladu bude shodný s příkladem předchozím:
Hello world!
11. Uvolnění paměti před jejím použitím
Kvůli tomu, že se o paměť používanou na straně céčka musíme explicitně starat, může nastat situace, kdy se do kódu zanesou poměrně typické „céčkovské“ chyby, například dealokace paměti ještě předtím, než je obsah této paměti použit. Výsledek je v tomto případě nedefinovaný – program může zhavarovat, může zdánlivě běžet bez chyby nebo bude obsah paměti změněn (což je u Go pravděpodobnější, než v čistém céčku):
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func main() { cs := C.CString("Hello world!") C.free(unsafe.Pointer(cs)) C.puts(cs) }
Může se stát, že tento program zhavaruje, ovšem pravděpodobněji na standardní výstup vypíše náhodný řetězec (a záleží jen na náhodě, jak bude dlouhý, tj. kdy se narazí na první nulový bajt):
@#@
12. Dvojí zavolání funkce C.free()
Druhou poměrně typickou chybou je dvojí volání funkce free(), přičemž první volání provede korektní dealokaci, ale druhé volání se pokusí dealokovat stejný blok paměti. Ani tento problém nedokáže překladač jazyka Go detekovat:
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe" func main() { cs := C.CString("Hello world!") C.puts(cs) C.free(unsafe.Pointer(cs)) C.free(unsafe.Pointer(cs)) }
V tomto případě většinou dojde k okamžitému pádu aplikace:
SIGABRT: abort PC=0x7f4cc7251c37 m=0 sigcode=18446744073709551610 goroutine 0 [idle]: runtime: unknown pc 0x7f4cc7251c37 stack: frame={sp:0x7ffe1f450d08, fp:0x0} stack=[0x7ffe1ec52188,0x7ffe1f4511b0) 00007ffe1f450db8: 0000000000000000 0000000000000000 00007ffe1f450dc8: 000000770000006e 0000000000000000 00007ffe1f450dd8: 00007ffe1f450dff 000000000043bc5f <runtime.findfunc+47> 00007ffe1f450de8: 000000000044ab31 <runtime.goexit+1> 000000000000007c 00007ffe1f450df8: 00007ffe1f451100 00000000004405e8 <runtime.gentraceback+6184> goroutine 1 [syscall]: runtime.cgocall(0x451a20, 0xc000038730, 0xc000de3040) /opt/go/src/runtime/cgocall.go:128 +0x5e fp=0xc000038700 sp=0xc0000386c8 pc=0x403c3e main._Cfunc_free(0xde31a0) _cgo_gotypes.go:59 +0x41 fp=0xc000038730 sp=0xc000038700 pc=0x4516d1 main.main.func2(0xde31a0) /home/tester/temp/go-root/article_36/18_double_free.go:12 +0x56 fp=0xc000038768 sp=0xc000038730 pc=0x451966 main.main() /home/tester/temp/go-root/article_36/18_double_free.go:12 +0x65 fp=0xc000038798 sp=0xc000038768 pc=0x451885 runtime.main() /opt/go/src/runtime/proc.go:201 +0x207 fp=0xc0000387e0 sp=0xc000038798 pc=0x425727 runtime.goexit() /opt/go/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc0000387e8 sp=0xc0000387e0 pc=0x44ab31
13. Nepřímé čtení proměnné errno
Další velmi užitečnou funkcí pseudobalíčku „C“ je práce s proměnnou errno (viz též man 3 errno). Tato proměnná, kterou céčkoví programátoři dobře znají, obsahuje kód poslední chyby, přičemž pro každý celočíselný kód chyby existuje i příslušná symbolická konstanta: EACCES, ECANCELED, ENOENT atd.
Kód poslední chyby můžeme přečíst i idiomatickým kódem v Go – získáním většího množství návratových kódů funkce. Ukažme si konkrétní příklad, a to volání matematické funkce pro výpočet druhé odmocniny. Tato céčková funkce vrací vypočtený výsledek a současně může nastavit proměnnou errno v případě, kdy se snažíme o výpočet druhé odmocniny ze záporného čísla (s komplexními čísly se zde nepracuje). V Go ovšem můžeme z této funkce získat dvě hodnoty – jak vypočtenou druhou odmocninu, tak i objekt představující chybu (popř. nil pokud k chybě nedošlo):
y, err := C.sqrt(C.double(nějaké číslo))
Z následujícího úryvku kódu je zřejmé, že se jedná o kratší a lépe čitelný kód, než explicitní přístup k proměnné errno:
package main // #include <math.h> // #cgo LDFLAGS: -lm import "C" import "fmt" func main() { y, err := C.sqrt(C.double(100.0)) fmt.Printf("result=%v err=%v\n", y, err) y, err = C.sqrt(C.double(-1.0)) fmt.Printf("result=%v err=%v\n", y, err) y, err = C.sqrt(C.double(100.0)) fmt.Printf("result=%v err=%v\n", y, err) }
Výsledek běhu tohoto demonstračního příkladu:
result=10 err=<nil.h> result=NaN err=numerical argument out of domain result=10 err=<nil.h>
14. Deklarace céčkovské funkce v komentáři
Podívejme se ještě na jednu možnost, kterou nám jazyk Go (a nástroj cgo) nabízí. V komentáři uvedeném před importem pseudobalíčku „C“ je možné deklarovat jak céčkovské datové typy pomocí typedef, tak i celé funkce. Tyto funkce jsou ihned volatelné z dalšího programového kódu. Můžeme se o tom velmi snadno přesvědčit:
package main // int add(int a, int b) { // return a+b; // } import "C" import "fmt" func main() { x := C.add(C.int(1), C.int(2)) fmt.Printf("result=%x\n", x) }
15. Práce s řetězci alokovanými funkcemi jazyka C
Ukažme si na závěr, jak vlastně můžeme (explicitně) pracovat s řetězci alokovanými funkcemi programovacího jazyka C. Pro alokaci řetězce můžeme použít buď funkci malloc nebo calloc. V případě, že se má jednat o řetězec s maximálně devatenácti znaky a ukončující nulou, použijeme volání:
s := C.calloc(20, 1)
Takový řetězec je možné předat například funkci fgets, ovšem po správném přetypování:
char_ptr := (*C.char)(s) C.fgets(char_ptr, 20, C.stdin)
Samozřejmě nesmíme zapomenout ani na uvolnění řetězce z paměti (zde nám ovšem void * naopak vyhovuje):
C.free(s)
Úplný zdrojový kód, který přečte řetězec ze standardního vstupu a následně vypíše jeho obsah, může vypadat takto:
package main // #include <stdio.h> // #include <stdlib.h> import "C" import "fmt" func main() { fmt.Print("? ") s := C.calloc(20, 1) char_ptr := (*C.char)(s) C.fgets(char_ptr, 20, C.stdin) fmt.Printf("result=%v\n", C.GoString(char_ptr)) C.free(s) }
16. Prohlédnutí kódu generovaného překladačem jazyka Go
V některých případech může být zajímavé si prohlédnout céčkový kód generovaný překladačem jazyka Go před jeho předáním do céčkového překladače. Pro tento účel můžeme zavolat nástroj cgo přímo, a to následujícím způsobem (namísto go build):
$ go tool cgo filename.go
Po spuštění tohoto nástroje by se měl vytvořit podadresář _obj, do něhož jsou uloženy zdrojové kódy generované překladačem jazyka C. Skutečně se jedná o zdrojové kódy, které mohou být předány překladači céčka:
$ ls -1 _obj 16_c_function.cgo1.go 16_c_function.cgo2.c _cgo_export.c _cgo_export.h _cgo_flags _cgo_gotypes.go _cgo_main.c _cgo_.o
17. Repositář s demonstračními příklady
Zdrojové kódy všech 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ě tři megabajty), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
18. 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