Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go

27. 12. 2019
Doba čtení: 41 minut

Sdílet

Ve výzkumu v oblastech numerických výpočtů, simulací, ML a AI se poměrně razantním způsobem prosadil jazyk Python. Ovšem i zde můžeme použít další programovací jazyky. Relativním nováčkem na tomto poli je jazyk Go.

Obsah

1. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go

2. Projekt Gonum Numerical Packages (Gonum)

3. Projekt Gomacro

4. Klávesové zkratky použitelné v interaktivní smyčce projektu Gomacro

5. Základní použití interaktivní smyčky REPL projektu Gomacro

6. Manipulace s maticemi (v REPL)

7. Zobrazení vybraného obsahu rozsáhlých matic

8. Transpozice a součet matic

9. Maticový součin a podobné operace

10. Použití projektu Gophernotes společně s Jupyter notebookem

11. Spuštění Gophernotes v Dockeru

12. Kombinace projektů Gophernotes, Gonum a Gomacro

13. Použití Markdownu

14. Matematická sazba

15. Víceřádkové vzorce

16. Načtení rastrových obrázků

17. Načtení vektorových obrázků ve formátu SVG

18. Obsah navazující části seriálu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go

„There is a tension, especially in scientific computing, between ease and simplicity“

V dnešním článku si popíšeme potenciálně velmi užitečný nástroj nazvaný Gophernotes, který uživatelům (a zdaleka se nemusí jednat pouze o vývojáře) používajícím programovací jazyk Go zpřístupňuje interaktivní prostředí založené na známém projektu Jupyter, který vznikl z neméně známého a používaného projektu IPython Notebook. Toto interaktivní prostředí, které se zobrazuje přímo ve webovém prohlížeči, obsahuje klasickou smyčku REPL (Read–Eval–Print–Loop), což mj. znamená, že se jednotlivé výrazy zapsané uživatelem mohou ihned vyhodnocovat s prakticky okamžitou zpětnou vazbou. Navíc však nástroj Gophernotes dokáže do okna prohlížeče vykreslovat základní grafy, a to jak s přímým využitím předaných dat (vektory či sekvence čísel), tak i při specifikaci funkce, jejíž průběh se má vykreslit (existují zde ovšem mnohá omezení, kterými se budu zabývat v navazujících kapitolách). Třešničkou na dortu je podpora pro práci se vzorci psanými v TeXu či LaTeXu.

Obrázek 1: Klasický IPython notebook – nástroj, který umožňoval interaktivní ovládání interpretru Pythonu z GUI, nabízel všechny možnosti konzolového IPythonu a navíc i podporoval práci s grafickými objekty (rastrové obrázky, grafy, diagramy atd.).

Celé grafické uživatelské rozhraní Gophernotes napodobuje diář (notebook), do kterého se zapisují jak poznámky, tak i programový kód a jeho výsledek, takže se tento systém může hodit i pro tvorbu (interaktivních) prezentací, použití sdílené pracovní plochy atd. Ostatně v tomto ohledu není přístup zvolený autory nijak nový ani přelomový, protože například i populární Matlab používá podobnou technologii (i když založenou na jiném programovacím jazyku).

D

Obrázek 2: Použití Pythonu v Jupyteru při výpočtu fraktálů. Složitější numerické výpočty jsou jednou z oblastí, v níž by bylo výhodnější použít jiný programovací jazyk, resp. přesněji jeho jádro propojené s Jupyterem.
 Zdroj

Již v úvodním odstavci jsme si řekli, že Gophernotes je založen na projektu Jupyter. Ve skutečnosti Gophernotes do Jupyteru doplňuje modul (takzvaný kernel) zajišťující interakci s jazykem Go, podobně jako existují další podobné moduly určené pro programovací jazyky Python, Julia, Lua, jazyk Hy atd. V případě jazyka Go je ovšem situace poněkud složitější, protože Go je primárně překladačem. Aby bylo možné zkombinovat možnosti interpretru a klasického překladače, vznikl projekt pojmenovaný Gomacro, o jehož některých možnostech se zmíníme v navazujících kapitolách.

Obrázek 3: Nejenom pro numerické výpočty může být ideální kombinací jazyk Julia a projekt Jupyter notebook.
 Zdroj

Poznámka: ve skutečnosti existuje hned několik kernelů pro Go: IGo, gopherlab a právě Gophernotes.

2. Projekt Gonum Numerical Packages (Gonum)

Samotný programovací jazyk Go obsahuje podporu pro práci s maticemi a řezy (ostatně se jedná o základní datové typy tohoto jazyka). Práce s těmito datovými strukturami je podporována i ve standardní knihovně jazyka. Ovšem například v porovnání se známou a velmi často používanou knihovnou NumPy ze světa Pythonu (nebo s možnostmi Matlabu či R) jsou možnosti standardní instalace Go v této oblasti mnohem menší. Ovšem některé operace, které známe z NumPy, byly implementovány v sadě knihoven, které jsou součástí projektu nazvaného jednoduše Gonum Numerical Packages. Tento projekt obsahuje zejména knihovnu pro práci s maticemi (naprosté základy si ukážeme níže a více se jim budeme věnovat příště), algoritmy lineární algebry, podporu pro tvorbu grafů, podporu práce s takzvanými „datovými rámci“ (ve světě Pythonu se používá pandas) atd.

Obrázek 4: Logo projektu Gonum Numerical Packages.

Poznámka: na tomto místě je však vhodné poznamenat, že integrace NumPy do Pythonu je mnohem lepší, než je tomu v případě projektu Gonum. Je tomu tak z toho důvodu, že jazyk Go nepodporuje přetěžování operátorů, takže například není možné implementovat maticové operace „přirozenou“ cestou (zrovna příklad NumPy ukazuje, že přetěžování operátorů, pokud je použito rozumně, může být velmi užitečné).

Samotnou sadu knihoven z projektu Gonum Numerical Packages nainstalujeme (pro aktivního uživatele) snadno, konkrétně příkazem „go get“:

$ go get -u gonum.org/v1/gonum/...
Poznámka: při instalaci více knihoven současně nezapomeňte na uvedení tří teček na konci cesty v „go get“.

S některými vlastnostmi knihovnu mat z projektu Gonum se setkáme po instalaci projektu Gomacro.

3. Projekt Gomacro

Jak jsme si již řekli v úvodní kapitole, aby bylo možné programovací jazyk Go zařadit do nástrojů typu Jupyter, je nutné, aby byl k dispozici buď přímo klasický interpret, nebo alespoň překladač umožňující postupný překlad jednotlivých výrazů, funkcí a metod s jejich následným spouštěním a zpracováním výsledků. A právě tato funkcionalita je nabízena projektem nazvaným Gomacro, který dokáže pracovat jako interpret jazyka Go a nabízí programátorům i plnohodnotnou smyčku REPL.

Instalace tohoto projektu se opět provede příkazem „go get“:

$ go get -u github.com/cosmos72/gomacro

Dále je nutné se přesvědčit o tom, že je adresář $HOME/go/bin zařazen do proměnné prostředí PATH. V opačném případě by totiž nebylo možné příkaz gomacro volat odkudkoli (což platí i pro další nástroje naprogramované v jazyku Go a instalované příkazem „go get“).

Pokud je $HOME/go/bin vložen do proměnné prostředí PATH, bude možné Gomacro spustit:

$ gomacro
 
// GOMACRO, an interactive Go interpreter with generics and macros
// Copyright (C) 2018-2019 Massimiliano Ghilardi <https://github.com/cosmos72/gomacro>
// License MPL v2.0+: Mozilla Public License version 2.0 or later <http://mozilla.org/MPL/2.0/>
// This is free software with ABSOLUTELY NO WARRANTY.
//
// Type :help for help
gomacro>
Poznámka: případné hlášení zobrazené níže znamená, že byly smazány zdrojové kódy Gomacra, což však jeho práci nijak zásadně neovlivní:
// warning: could not find package "github.com/cosmos72/gomacro" in $GOPATH = "/home/tester/go/", assuming package is located in "/home/tester/go/src/github.com/cosmos72/gomacro"

Aby bylo možné odlišit příkazy jazyka Go od nových příkazů zavedených Gomacrem, začínají příkazy Gomacra dvojtečkou:

gomacro> :help
 
// type Go code to execute it. example: func add(x, y int) int { return x + y }
 
// interpreter commands:
:debug EXPR        debug expression or statement interactively
:env [NAME]        show available functions, variables and constants
                   in current package, or from imported package NAME
:help              show this help
:inspect EXPR      inspect expression interactively
:options [OPTS]    show or toggle interpreter options
:package "PKGPATH" switch to package PKGPATH, importing it if possible
:quit              quit the interpreter
:unload "PKGPATH"  remove package PKGPATH from the list of known packages.
                   later attempts to import it will trigger a recompile
:write [FILE]      write collected declarations and/or statements to standard output or to FILE
                   use :opt Declarations and/or :opt Statements to start collecting them
// abbreviations are allowed if unambiguous.

Dále je možné prozkoumat výrazy jazyka Go:

gomacro> :inspect 1*(2+3)
 
1*(2+3) = {int 5}       // untyped.Lit
    0. Kind     = int   // untyped.Kind
    1. Val      = 5     // constant.Value
    2. basicTypes       = [<nil> 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 0x11060b0 <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0x11060b0 <nil> 0x11060b0]  // *[]xreflect.Type
// type ? for inspector help

Prozkoumat lze i volání funkcí, kdy se mj. zobrazí jejich výsledek:

gomacro> import "fmt"
 
gomacro> :inspect fmt.Printf("%d\n", 42)
 
// warning: expression returns 2 values, using only the first one: [int error]
42
fmt.Printf("%d\n", 42)  = 3     // int
// type ? for inspector help

Popř. lze vypsat metody aplikovatelné pro zvoleného příjemce (receiver):

inspect fmt.Printf("%d\n", 42)> methods
 
methods of int:
    m0. func (int).Add(int, int) int
    m1. func (int).And(int, int) int
    m2. func (int).AndNot(int, int) int
    m3. func (int).Cmp(int) int
    m4. func (int).Equal(int) bool
    m5. func (int).Less(int) bool
    m6. func (int).Lsh(int, uint8) int
    m7. func (int).Mul(int, int) int
    m8. func (int).Neg(int) int
    m9. func (int).Not(int) int
    m10. func (int).Or(int, int) int
    m11. func (int).Quo(int, int) int
    m12. func (int).Rem(int, int) int
    m13. func (int).Rsh(int, uint8) int
    m14. func (int).Sub(int, int) int
    m15. func (int).Xor(int, int) int

Výpis tzv. prostředí, tj. dostupných funkcí a datových typů:

gomacro> :env
 
// ----- builtin binds -----
Eval            = {0x1213270 func(interface{}, interface{}) interface{}}        // fast.Function
EvalKeepUntyped = {0x1213320 func(interface{}, interface{}) interface{}}        // fast.Function
EvalType        = {0x1213660 func(interface{}, interface{}) reflect.Type}       // fast.Function
Interp          = {0x1213240 func(interface{}) interface{}}     // fast.Function
MacroExpand     = {0x1214310 func(interface{}, interface{}) (go/ast.Node, bool)}        // fast.Function
MacroExpand1    = {0x1214400 func(interface{}, interface{}) (go/ast.Node, bool)}        // fast.Function
MacroExpandCodeWalk             = {0x12144f0 func(interface{}, interface{}) (go/ast.Node, bool)}        // fast.Function
Parse           = {0x1216310 func(string, interface{}) interface{}}     // fast.Function
append          = 0x120efd0     // fast.Builtin
cap             = 0x120fb30     // fast.Builtin
close           = 0x1210290     // fast.Builtin
complex         = 0x1210880     // fast.Builtin
copy            = 0x1211f00     // fast.Builtin
delete          = 0x1212ae0     // fast.Builtin
false           = {bool false}  // untyped.Lit
imag            = 0x1216e30     // fast.Builtin
len             = 0x1213960     // fast.Builtin
make            = 0x1214bd0     // fast.Builtin
new             = 0x1215bb0     // fast.Builtin
nil             = nil   //
panic           = 0x1216020     // fast.Builtin
print           = 0x1216a60     // fast.Builtin
println         = 0x1216a60     // fast.Builtin
real            = 0x1216e30     // fast.Builtin
recover         = 0x12180e0     // fast.Builtin
true            = {bool true}   // untyped.Lit
 
// ----- builtin types -----
Pointer         = unsafe.Pointer        // unsafe.Pointer
bool            = bool  // bool
byte            = uint8 // uint8
complex128      = complex128    // complex128
complex64       = complex64     // complex64
error           = error // interface
float32         = float32       // float32
float64         = float64       // float64
int             = int   // int
int16           = int16 // int16
int32           = int32 // int32
int64           = int64 // int64
int8            = int8  // int8
rune            = int32 // int32
string          = string        // string
uint            = uint  // uint
uint16          = uint16        // uint16
uint32          = uint32        // uint32
uint64          = uint64        // uint64
uint8           = uint8 // uint8
uintptr         = uintptr       // uintptr
 
// ----- main binds -----
fmt             = {fmt "fmt", 19 binds, 6 types}        // *fast.Import

4. Klávesové zkratky použitelné v interaktivní smyčce projektu gomacro

Vzhledem k tomu, že je gomacro vybaveno i interaktivní smyčkou REPL, je důležité, aby bylo možné editovat příkazový řádek, mít k dispozici historii příkazového řádku (s možností vyhledávání) atd. Pro tento účel používá gomacro knihovnu https://github.com/peterh/liner naprogramovanou v jazyce Go, která je inspirována céčkovou knihovnou linenoise (ke které se ještě na stránkách Rootu vrátíme). V této kapitole jsou vypsány vybrané klávesové zkratky, které jsou ve výchozím nastavení použity v interaktivní smyčce projektu gomacro. Většina zkratek vychází z Emacsu a uživatelé je mohou znát například i z editoru Joe, z shellu (BASH atd.), pokud ovšem není nastaven režim emulující chování textového editoru Vi/Vim. Pro větší přehlednost jsou příkazy rozděleny do několika skupin.

Příkazy pro přesuny kurzoru

Základní příkazy pro přesun kurzoru používají kombinaci kláves Ctrl+znak, Alt+znak popř. alternativně Esc, znak v případě, že zkratky Alt+znak kolidují s emulátorem terminálu (například vyvolávají příkazy z menu). V případě, že je terminál správně nakonfigurován, měly by fungovat i kurzorové šipky, kombinace Ctrl+šipky a navíc i klávesy Home a End (se zřejmou funkcí):

Klávesa Alternativa Význam
Ctrl+B šipka doleva přesun kurzoru na předchozí znak
Ctrl+F šipka doprava přesun kurzoru na následující znak
     
Alt+B Ctrl+šipka doleva přesun kurzoru na předchozí slovo
Alt+F Ctrl+šipka doprava přesun kurzoru na další slovo
Esc, B   shodné s klávesovou zkratkou Alt+B
Esc, F   shodné s klávesovou zkratkou Alt+F
     
Ctrl+A Home přesun kurzoru na začátek řádku
Ctrl+E End přesun kurzoru na konec řádku

Mazání textu, práce s yank bufferem

Pro přesun části textu v rámci editovaného řádku (nebo na nějaký jiný řádek atd.) se používá takzvaný yank buffer (v Emacsu se používá označení kill ring), do něhož se smazaný text uloží. Pro vložení takto smazaného textu do jiné oblasti se používá operace nazvaná yank (odpovídá operaci paste). Některé dále uvedené příkazy dokážou s yank bufferem pracovat (obdoba cut/copy/paste):

Klávesa Význam
Ctrl+H smaže znak před kurzorem
BackSpace smaže znak před kurzorem
   
Ctrl+K smaže text od kurzoru do konce řádku
Ctrl+U smaže text od začátku řádku do pozice kurzoru
Ctrl+W smaže předchozí slovo
Alt+D smaže následující slovo
   
Ctrl+Y vloží text z yank bufferu na místo, na němž se nachází kurzor (yank neboli paste)
Alt+Y po operaci Ctrl+Y dokáže rotovat historií a obnovit tak (před)předchozí smazaný text
   
Ctrl+D smaže jeden znak (pokud je ovšem na řádku nějaký obsah, jinak typicky ukončí aplikaci)

Práce s historií dříve zadaných příkazů

Velmi užitečné klávesové zkratky umožňují procházet historií dříve zadaných příkazů. Pro vyhledávání v historii slouží zkratka Ctrl+R:

Klávesa Význam
Ctrl+P průchod historií – předchozí text
Ctrl+N průchod historií – následující text
Ctrl+R zpětné (interaktivní) vyhledávání v historii

Některé další dostupné příkazy

Mezi další užitečné zkratky patří režim completeru, v němž se gomacro snaží nalézt symbol z tabulky funkcí či metod:

Klávesa Význam
Tab implicitní klávesa pro zavolání completeru
Shift+Tab návrat na předchozí návrh doplnění jména funkce/metody
Ctrl+T prohození dvou znaků (před kurzorem a na pozici kurzoru)
   
Ctrl+L smazání obrazovky
Poznámka: v případě volání funkcí a metod bere completer do úvahy i kontext, takže se například pro textu fmt. nabídnou pouze funkce z balíčku „fmt“.

5. Základní použití interaktivní smyčky REPL projektu Gomacro

V této kapitole se seznámíme s některými možnostmi, které nám interaktivní smyčka projektu Gomacro nabízí. Pokud na vstup zadáme nějaký výraz (aritmetický, logický, výraz s řetězci atd.), je tento výraz přeložen a ihned vyhodnocen. Jeho výsledek se vypíše na výstup, stejně, jako by jazyk Go byl interpretován:

gomacro> 1+1
{int 2} // untyped.Lit
Poznámka: povšimněte si, že se nevypíše pouze výsledek výrazu, ale i jeho typ, což může být velmi užitečné, jak uvidíme dále.

Můžeme provést i import knihovny (balíčku):

gomacro> import "fmt"

U funkce či výrazu vracejícího více hodnot se zobrazí všechny hodnoty. V případě funkce i se jmény a typy návratových hodnot (velmi praktické, protože ihned vidíme, že například funkce fmt.Println vrací ve druhé návratové hodnotě příznak chyby):

gomacro> fmt.Println("test")
test
5       // int
<nil>   // error

Deklarovat můžeme i proměnné, a to libovolného typu, včetně řezů (slice):

gomacro> var a []int
gomacro> a
[]      // []int
 
gomacro> a=append(a, 10)
gomacro> a
[10]    // []int

Zavolání metod objektů, zde konkrétně metody řezu:

gomacro> a.Cap()
1       // int
 
gomacro> a.Len()
1       // int

Použít můžeme i programovou smyčku:

gomacro> for i := 1; i < 10; i++ {
. . . .    a=append(a, i)
. . . .  }
 
gomacro> a
[10 1 2 3 4 5 6 7 8 9]  // []int
 
gomacro> a.Cap()
16      // int
 
gomacro> a.Len()
10      // int

Další příklad – funkce s několika návratovými hodnotami:

gomacro> func x(i int) (int, float64, byte) {
. . . .      return i, 1.0/float64(i), byte(i)
. . . .  }
 
gomacro> x(10)
10      // int
0.1     // float64
10      // uint8

Funkce vracející chybu:

gomacro> f, err := os.Open("foobarbaz")
gomacro> f
   // *os.File
gomacro> err
open foobarbaz: no such file or directory       // error

Funkce, která naopak otevře existující soubor:

gomacro> f, err := os.Open(".bashrc")
 
gomacro> f
&{0xc00048d260} // *os.File
gomacro> err
<nil>   // error

Malá připomínka, že k hodnotě nil je přiřazen i typ:

gomacro> var ii interface{} = nil
gomacro> ii
<nil>   // interface{}
 
gomacro> var p *int = nil
gomacro> p
<nil>   // *int
 
gomacro> var m map[string]string = nil
gomacro> m
map[]   // map[string]string

6. Manipulace s maticemi (v REPL)

Nyní, když máme nainstalovánu jak interaktivní smyčku REPL (Gomacro) i projekt Gonum s několika numerickými knihovnami, si můžeme ukázat, jak se manipuluje s maticemi, které v oblasti numerických výpočtů mnohdy představují základní datový typ.

Používat budeme dva balíčky – standardní balíček „fmt“ a balíček „mat“ z Gonum:

gomacro> import "fmt"
 
gomacro> import "gonum.org/v1/gonum/mat"
// debug: looking for package "gonum.org/v1/gonum/mat" ...
// debug: compiling "/home/ptisnovs/go/src/gomacro.imports/gonum.org/v1/gonum/mat/mat.go" ...

Pro reprezentaci matic se používá několik struktur. Základem je je dense matrix používaná pro matice běžné velikosti, které obsahují libovolné prvky (a kde typicky nepřevažují prvky nulové):

gomacro> zero := mat.NewDense(5, 6, nil)
 
gomacro> zero
&{{5 6 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 6} 5 6}   // *gonum.org/v1/gonum/mat.Dense

Naplnění matice daty:

gomacro> m2 := mat.NewDense(3, 4, []float64{1,2,3,4,5,6,7,8,9,10,11,12})
Poznámka: zde můžeme vidět, že práce s maticemi není tak elegantní, jako je tomu v knihovně NumPy.

7. Zobrazení vybraného obsahu rozsáhlých matic

Nyní se pokusme vytvořit relativně velkou matici o rozměrech 100×100 prvků:

gomacro> big := mat.NewDense(100, 100, nil)

Matici můžeme naplnit daty, a to pomocí metody Set (vyplníme jen prvky na hlavní úhlopříčce):

gomacro> for i := 0; i < 100; i++ {
. . . .        big.Set(i, i, 1)
. . . .    }

Přímý tisk hodnoty takové matice ovšem není přehledný:

gomacro> big
&{{100 100 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...
...
...
0 0 0 0 0 1] 100} 100 100}      // *gonum.org/v1/gonum/mat.Dense

Ani přímý tisk přes standardní funkci fmt.Printf není ideální:

gomacro> fmt.Printf("%v\n", big)
&{{100 100 [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...
...
...

Výhodnější je použití funkce mat.Formatted, které se ve druhém parametru předá oddělovač hodnot na řádku a ve třetím parametru pak informace o tom, kolik mezních sloupců a řádků se má vytisknout. Pokud nám postačuje tisk prvních a posledních tří řádků a sloupců, lze použít:

gomacro> fmt.Printf("excerpt big identity matrix: %v\n\n",
. . . .        mat.Formatted(big, mat.Prefix(" "), mat.Excerpt(3)))
 
excerpt big identity matrix: Dims(100, 100)
 ⎡1  0  0  ...  ...  0  0  0⎤
 ⎢0  1  0            0  0  0⎥
 ⎢0  0  1            0  0  0⎥
  .
  .
  .
 ⎢0  0  0            1  0  0⎥
 ⎢0  0  0            0  1  0⎥
 ⎣0  0  0  ...  ...  0  0  1⎦
 
261     // int
<nil>   // error

V REPLu navíc nemusíme volat funkci fmt.Printf, protože se výsledná hodnota zobrazí automaticky:

gomacro> mat.Formatted(big, mat.Prefix(" "), mat.Excerpt(3))
 
Dims(100, 100)
 ⎡1  0  0  ...  ...  0  0  0⎤
 ⎢0  1  0            0  0  0⎥
 ⎢0  0  1            0  0  0⎥
  .
  .
  .
 ⎢0  0  0            1  0  0⎥
 ⎢0  0  0            0  1  0⎥
 ⎣0  0  0  ...  ...  0  0  1⎦   // fmt.Formatter

Dtto, ale pro mezních pět řádků a sloupců:

gomacro> mat.Formatted(big, mat.Prefix(" "), mat.Excerpt(5))
 
Dims(100, 100)
 ⎡1  0  0  0  0  ...  ...  0  0  0  0  0⎤
 ⎢0  1  0  0  0            0  0  0  0  0⎥
 ⎢0  0  1  0  0            0  0  0  0  0⎥
 ⎢0  0  0  1  0            0  0  0  0  0⎥
 ⎢0  0  0  0  1            0  0  0  0  0⎥
  .
  .
  .
 ⎢0  0  0  0  0            1  0  0  0  0⎥
 ⎢0  0  0  0  0            0  1  0  0  0⎥
 ⎢0  0  0  0  0            0  0  1  0  0⎥
 ⎢0  0  0  0  0            0  0  0  1  0⎥
 ⎣0  0  0  0  0  ...  ...  0  0  0  0  1⎦       // fmt.Formatter

8. Transpozice a součet matic

Mezi další podporované základní maticové operace patří transpozice a součet matic.

Nejdříve vytvoříme proměnnou pro uložení výsledku (nealokuje se žádná další paměť):

gomacro> var c mat.Dense
gomacro> c
{mat:{0 0 [] 0} capRows:0 capCols:0}    // gonum.org/v1/gonum/mat.Dense

Dále vytvoříme dvě matice se třemi řádky a čtyřmi prvky na řádku:

gomacro> m1 := mat.NewDense(3, 4, {})
gomacro> m1
&{{3 4 [0 0 0 0 0 0 0 0 0 0 0 0] 4} 3 4}        // *gonum.org/v1/gonum/mat.Dense
 
gomacro> m2 := mat.NewDense(3, 4, []float64{1,2,3,4,5,6,7,8,9,10,11,12})
gomacro> m2
&{{3 4 [1 2 3 4 5 6 7 8 9 10 11 12] 4} 3 4}     // *gonum.org/v1/gonum/mat.Dense

Obě matice vytiskneme v čitelném formátu:

gomacro> mat.Formatted(m1)
⎡0  0  0  0⎤
⎢0  0  0  0⎥
⎣0  0  0  0⎦    // fmt.Formatter
 
gomacro> mat.Formatted(m2)
⎡ 1   2   3   4⎤
⎢ 5   6   7   8⎥
⎣ 9  10  11  12⎦        // fmt.Formatter

Výpočet transponované matice s jejím následným vytištěním:

gomacro> m3 := m2.T()
gomacro> mat.Formatted(m3)
⎡ 1   5   9⎤
⎢ 2   6  10⎥
⎢ 3   7  11⎥
⎣ 4   8  12⎦    // fmt.Formatter

Součet matic je řešen metodou:

gomacro> c.Add(m3, m3)
gomacro> mat.Formatted(&c)
⎡ 2  10  18⎤
⎢ 4  12  20⎥
⎢ 6  14  22⎥
⎣ 8  16  24⎦    // fmt.Formatter
Poznámka: v této knihovně vždy platí – funkce ani metody nemění obsah svých parametrů (matic). Změnit lze obsah jediné hodnoty – příjemce (receiveru) u metod.

9. Maticový součin a podobné operace

Podporována je i operace maticového součinu, ale pochopitelně pouze za předpokladu, že počet sloupců první matice odpovídá počtu řádků matice druhé:

gomacro> var c mat.Dense
gomacro> c.Mul(m3, m2)
mat: dimension mismatch

Pokud matice m2 a m3 předáme ve správném pořadí, bude možné matice vynásobit a uložit výsledek do příjemce:

gomacro> c.Mul(m2, m3)
 
gomacro> mat.Formatted(&c)
⎡ 30   70  110⎤
⎢ 70  174  278⎥
⎣110  278  446⎦ // fmt.Formatter

Provést lze i násobení dvou matic prvek po prvku (což ovšem neodpovídá maticovému násobení):

gomacro> var c mat.Dense
gomacro> c.MulElem(m3, m3)
gomacro> mat.Formatted(&c)
⎡  1   25   81⎤
⎢  4   36  100⎥
⎢  9   49  121⎥
⎣ 16   64  144⎦ // fmt.Formatter

10. Použití projektu Gophernotes společně s Jupyter notebookem

Nástroj Gophernotes je založen na klasické technologii klient-server, kde klientem je webový prohlížeč spuštěný u uživatele (či uživatelů) a serverem je Jupyter s přidaným modulem (kernelem) pro jazyk Go vybaveným výše popsaným projektem gomacro. Výraz, popř. blok výrazů představujících programový kód napsaný v programovacím jazyce Go, je po stlačení klávesové zkratky Shift+Enter přenesen na server, kde je zpracován a výsledek je poslán zpět do prohlížeče.

JavaScriptový kód na straně prohlížeče zajistí interpretaci získaných výsledků a jejich zařazení na správné místo do dynamické webové stránky (jedná se vlastně o dnes tak populární SPA – Single Page Application se všemi přednostmi a zápory, které toto řešení přináší). Výsledky poslané serverem na klienta mohou být ve skutečnosti různého typu; typicky se jedná o fragment HTML (tabulky atd.), obrázek typu SVG (graf, histogram), rastrový obrázek (graf získaný například ze systému R), vzorec vykreslený z TeXového či LaTeXového zdrojového kódu apod. Samotná architektura nástroje Jupyter je otevřená a poměrně snadno rozšiřitelná, což znamená, že je v případě potřeby možné přidat například další typy grafů apod.

Existují i podobně koncipované projekty. Na stránkách Rootu jsme se například seznámili s projektem Gorilla REPL, který je určen pro programovací jazyk Clojure:

Obrázek 5: Interaktivní prostředí nástroje Gorilla REPL spuštěné v běžném webovém prohlížeči (zde konkrétně ve Firefoxu).

Obrázek 6: Standardní grafy jsou v Gorilla REPL do stránky vkládány ve formátu SVG.

Obrázek 7: Ukázka použití jednoduchého sloupcového grafu.

11. Spuštění Gophernotes v Dockeru

Nejjednodušší způsob, jakým lze spustit Gophernotes i se všemi potřebnými závislostmi, spočívá v použití Dockeru, protože již existuje připravený obraz obsahující Gophernotes, Jupyter, gomacro i další knihovny pro numerické výpočty a zpracování dat. Následující příkaz zajistí stažení obrazů, spuštění Gophernotesu a namapování HTTP serveru (Jupyter) na port 8888:

$ docker run -it -p 8888:8888 gopherdata/gophernotes:latest-ds
 
Unable to find image 'gopherdata/gophernotes:latest-ds' locally
Trying to pull repository docker.io/gopherdata/gophernotes ...
sha256:e2ef4a5b318604b8e5116fcf470e11fecbb2c18631cb73bdbed46ed026e862a6: Pulling from docker.io/gopherdata/gophernotes
a44d943737e8: Pull complete
0bbfb29b138b: Pull complete
ef49c0fa046c: Pull complete
Digest: sha256:e2ef4a5b318604b8e5116fcf470e11fecbb2c18631cb73bdbed46ed026e862a6
Status: Downloaded newer image for docker.io/gopherdata/gophernotes:latest-ds
[I 15:14:32.110 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
[I 15:14:32.998 NotebookApp] Serving notebooks from local directory: /
[I 15:14:32.999 NotebookApp] The Jupyter Notebook is running at:
[I 15:14:33.000 NotebookApp] http://(6c7428d3f7f9 or 127.0.0.1):8888/?token=f4d754332b4be755cfb351018840af76767e80829d7dfc61
[I 15:14:33.000 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 15:14:33.006 NotebookApp]
 
    To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
    Or copy and paste one of these URLs:
        http://(6c7428d3f7f9 or 127.0.0.1):8888/?token=f4d754332b4be755cfb351018840af76767e80829d7dfc61
Poznámka: povšimněte si, že se zobrazil i token, který použijeme pro přihlášení a založení nového diáře.

12. Kombinace projektů Gophernotes, Gonum a Gomacro

„There is a tension, especially in scientific computing, between ease and simplicity“

Do adresního řádku webového browseru napíšeme adresu: http://127.0.0.1:8888.

Obrázek 8: Prohlížeč se zeptá na token, který zkopírujeme ze zprávy vypsané po spuštění Dockeru s gophernotesem.

Obrázek 9: Grafické uživatelské rozhraní Jupyteru s Gophernotesem.

Obrázek 10: Zprávy zapisované na chybový výstup jsou podbarveny červeně, zprávy zapisované na výstup standardní nemají podbarvení žádné (implicitní barvou je bílé pozadí).

Obrázek 11: Formátování matic tak, jak jsme si to ukázali v předchozích kapitolách.

13. Použití Markdownu

Vzhledem k tomu, že je možné projekt Jupyter použít i pro tvorbu prezentací, asi nás nepřekvapí, že je podporována tvorba poznámek, které mohou být naformátovány. Podporován je především známý a široce používaný formátovací jazyk Markdown. Podívejme se na následující příklad, v němž je Markdown použit pro zobrazení textu neproporcionálním písmem, tučným písmem a kurzivou:

Obrázek 12: Použití funkce Display.markdown.

14. Matematická sazba

Podporována je i matematická sazba odvozená od možností TeXu a LaTeXu. Příkladem může být zápis vzorce s integrálem a zlomkem:

F(x) &= \int^a_b \frac{1}{3}x^3

Další dva příklady ukazují použití horních indexů (mocnin), zlomku a zápisu druhé odmocniny:

Display(display.Math(`x^2+y^2`))
Display(display.Math(`\frac{1}{\sqrt{x}}`))
Poznámka: povšimněte si, že se řetězce zapisují do zpětných apostrofů. Díky tomuto zápisu lze v jazyce Go do řetězců zapsat libovolné znaky bez nutnosti jejich uvození zpětným lomítkem, což je právě u matematických vzorců TeXu a LaTeXu velmi častý znak.

Obrázek 13: Výsledek zobrazení vzorce \frac{1}{\sqrt{x}} .

15. Víceřádkové vzorce

Použít lze i víceřádkovou sazbu vzorců. Časté bývá použití matic, na jejichž začátku a konci musíme použít „velké“ hranaté závorky (namísto pouhého zápisu [ a ]):

Display(display.Math(`\left[
\begin{matrix}
1 & 0\\
0 & 1
\end{matrix}
\right]`))

Obrázek 14: Matice vykreslená TeXovským formátovačem.

Podobný zápis je vyžadován i u složitějších vzorců se zlomky, integrály, sumami, limity atd.:

Display(display.Math(`
 \left[  \frac{ N } { \left( \frac{L}{p} \right)  - (m+n) }  \right]
`))

Obrázek 14: Složený zlomek vykreslený TeXovským formátovačem.

16. Načtení rastrových obrázků

Velmi často se setkáme s nutností zobrazit přímo v diáři rastrový obrázek. Ten může vzniknout několika způsoby, typicky se však jedná (ve světě výpočtů, simulací, ML atd.) o nějaký graf (heatmap atd.), výsledek aplikace rastrových operací na vstupní data atd. Pro zobrazení rastrového obrázku lze použít funkce dostupné z balíčku display, který je automaticky načten při inicializaci diáře, takže nemusíme provádět jeho explicitní import. V následujícím příkladu je ukázáno, jak lze načíst obrázek z externího zdroje (stáhneme ho pomocí http.Get) a zobrazit ho funkcí display.PNG (obrázek je reprezentován řezem bajtů obsahujícím jeho podobu zakódovanou do PNG – včetně hlaviček, palety, metadat atd.). Podobné funkce pochopitelně existují i pro rastrové obrázky uložené ve formátu JPEG či GIF:

import (
    "image"
    "net/http"
    "io/ioutil"
)
 
resp, err := http.Get("https://github.com/gopherdata/gophernotes/raw/master/files/gophernotes-logo.png")
bytes, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
display.PNG(bytes)
Poznámka: jedná se o příklad převzatý přímo z dokumentace projektu Gophernotes.

Obrázek 15: Rastrový obrázek s logem projektu Gophernotes načtený přímo do diáře.

17. Načtení vektorových obrázků ve formátu SVG

Zmiňme se o další užitečné vlastnosti projektu Gophernotes v kombinaci s Jypyterem. Jedná se o schopnost zobrazit přímo do vytvářeného diáře diagram, graf či nárys uložený do vektorového formátu SVG (Scalable Vector Graphics). Pro tento účel se používá funkce display.SVG, které se předá řez bajtů obsahující data s popisem SVG. Ta mohou vzniknout různým způsobem – lze je stáhnout, vytvořit programově atd. atd.:

resp, err := http.Get("http://jupyter.org/assets/nav_logo.svg")
bytes, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
display.SVG(string(bytes))
Poznámka: opět se jedná o příklad převzatý přímo z dokumentace projektu Gophernotes.

Obrázek 16: Logo projektu Jupyter je uloženo do vektorového formátu SVG a je ho tak možné přímo stáhnout a zobrazit v diáři.

bitcoin školení listopad 24

18. Obsah navazující části seriálu

Možností, která nám nabízí kombinace projektů Gomacro, Gonum a Gophernotes, je pochopitelně mnohem více, než bylo naznačeno v předchozích kapitolách. I z tohoto důvodu se s touto trojicí projektů setkáme i v navazujících částech seriálu o programovacím jazyce Go.

19. 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ě pět až šest megabajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 mat01.go vytvoření matice konstruktorem mat.NewDense https://github.com/tisnik/go-root/blob/master/article48/mat01.go
2 mat02.go vytištění obsahu matice funkcí mat.Formatted https://github.com/tisnik/go-root/blob/master/article48/mat02.go
3 mat03.go vytištění obsahu rozsáhlé matice https://github.com/tisnik/go-root/blob/master/article48/mat03.go
4 mat04.go vytištění obsahu rozsáhlé matice funkcí mat.Formatted https://github.com/tisnik/go-root/blob/master/article48/mat04.go
5 mat05.go vytištění vybrané části rozsáhlé matice https://github.com/tisnik/go-root/blob/master/article48/mat05.go
6 mat06.go vytištění vybrané části rozsáhlé matice https://github.com/tisnik/go-root/blob/master/article48/mat06.go
7 mat07.go transpozice matice https://github.com/tisnik/go-root/blob/master/article48/mat07.go
8 mat08.go součet a součin matic https://github.com/tisnik/go-root/blob/master/article48/mat08.go
9 mat09.go použití rozhraní mat.Matrix https://github.com/tisnik/go-root/blob/master/article48/mat09.go
10 mat10.go výpočet inverzní matice https://github.com/tisnik/go-root/blob/master/article48/mat10.go

20. Odkazy na Internetu

  1. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  2. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  3. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  4. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  5. gonum
    https://github.com/gonum
  6. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  7. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  8. Gonum Numerical Packages
    https://www.gonum.org/
  9. Stránky projektu MinIO
    https://min.io/
  10. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  11. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  12. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  13. Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
    https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/
  14. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  15. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  16. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  17. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  18. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  19. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  20. Ginkgo
    http://onsi.github.io/ginkgo/
  21. Gomega
    https://onsi.github.io/gomega/
  22. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  23. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  24. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  25. Balíček goexpect
    https://github.com/google/goexpect
  26. Balíček go-expect
    https://github.com/Netflix/go-expect
  27. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  28. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  29. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  30. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  31. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  32. goblin na GitHubu
    https://github.com/franela/goblin
  33. Mocha framework
    https://mochajs.org/
  34. frisby na GitHubu
    https://github.com/verdverm/frisby
  35. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  36. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  37. Cucumber for golang
    https://github.com/DATA-DOG/godog
  38. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  39. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  40. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  41. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  42. xml.org
    http://www.xml.org/
  43. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  44. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  45. JSON to YAML
    https://www.json2yaml.com/
  46. Data Format Converter
    https://toolkit.site/format.html
  47. Viper na GitHubu
    https://github.com/spf13/viper
  48. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  49. The fantastic ORM library for Golang
    http://gorm.io/
  50. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  51. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  52. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  53. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  54. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  55. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  56. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  57. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  58. Sémantické verzování
    https://semver.org/
  59. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  60. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  61. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  62. Modules
    https://github.com/golang/go/wi­ki/Modules
  63. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  64. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  65. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  66. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  67. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  68. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  69. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  70. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  71. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  72. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  73. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  74. gopls
    https://github.com/golang/go/wi­ki/gopls
  75. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  76. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  77. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  78. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  79. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  80. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  81. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  82. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  83. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  84. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  85. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  86. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  87. Package trace
    https://golang.org/pkg/runtime/trace/
  88. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  89. Command trace
    https://golang.org/cmd/trace/
  90. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  91. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  92. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  93. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  94. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  95. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  96. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  97. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  98. 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/
  99. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  100. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  101. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  102. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  103. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  104. The LLDB Debugger
    http://lldb.llvm.org/
  105. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  106. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  107. 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
  108. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  109. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  110. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  111. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  112. 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/
  113. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  114. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  115. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  116. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  117. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  118. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  119. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  120. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  121. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  122. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  123. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  124. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  125. go-cron
    https://github.com/rk/go-cron
  126. gocron
    https://github.com/jasonlvhit/gocron
  127. clockwork
    https://github.com/whiteShtef/cloc­kwork
  128. clockwerk
    https://github.com/onatm/clockwerk
  129. JobRunner
    https://github.com/bamzi/jobrunner
  130. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  131. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  132. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  133. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  134. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  135. go-prompt
    https://github.com/c-bata/go-prompt
  136. readline
    https://github.com/chzyer/readline
  137. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  138. go-readline
    https://github.com/fiorix/go-readline
  139. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  140. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  141. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  142. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  143. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  144. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  145. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  146. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  147. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  148. Editline Library (libedit)
    http://thrysoee.dk/editline/
  149. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  150. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  151. WinEditLine
    http://mingweditline.sourceforge.net/
  152. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  153. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  154. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  155. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  156. history(3) – Linux man page
    https://linux.die.net/man/3/history
  157. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  158. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  159. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  160. Balíček ogletest
    https://github.com/jacobsa/ogletest
  161. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  162. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  163. package testing
    https://golang.org/pkg/testing/
  164. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  165. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  166. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  167. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  168. GoConvey
    http://goconvey.co/
  169. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  170. 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
  171. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  172. package gg
    https://godoc.org/github.com/fo­gleman/gg
  173. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  174. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  175. The Go image package
    https://blog.golang.org/go-image-package
  176. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  177. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  178. YAML
    https://yaml.org/
  179. edn
    https://github.com/edn-format/edn
  180. Smile
    https://github.com/FasterXML/smile-format-specification
  181. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  182. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  183. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  184. Introducing JSON
    http://json.org/
  185. Package json
    https://golang.org/pkg/encoding/json/
  186. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  187. Go by Example: JSON
    https://gobyexample.com/json
  188. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  189. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  190. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  191. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  192. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  193. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  194. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  195. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  196. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  197. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  198. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  199. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  200. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  201. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  202. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  203. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  204. Algorithms to Go
    https://yourbasic.org/
  205. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  206. 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/
  207. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  208. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  209. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  210. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  211. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  212. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  213. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  214. The Go Programming Language (home page)
    https://golang.org/
  215. GoDoc
    https://godoc.org/
  216. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  217. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  218. The Go Programming Language Specification
    https://golang.org/ref/spec
  219. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  220. Package builtin
    https://golang.org/pkg/builtin/
  221. Package fmt
    https://golang.org/pkg/fmt/
  222. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  223. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  224. Learning Go
    https://www.miek.nl/go/
  225. Go Bootcamp
    http://www.golangbootcamp.com/
  226. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  227. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  228. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  229. The Go Blog
    https://blog.golang.org/
  230. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  231. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  232. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  233. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  234. 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
  235. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  236. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  237. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  238. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  239. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  240. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  241. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  242. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  243. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  244. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  245. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  246. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  247. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  248. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  249. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  250. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  251. 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/
  252. 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
  253. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  254. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  255. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  256. Go vs. Python
    https://www.peterbe.com/plog/govspy
  257. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  258. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  259. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  260. Go by Example: Slices
    https://gobyexample.com/slices
  261. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  262. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  263. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  264. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  265. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  266. nils In Go
    https://go101.org/article/nil.html
  267. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  268. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  269. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  270. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  271. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  272. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  273. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  274. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  275. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  276. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  277. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  278. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  279. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  280. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  281. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  282. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  283. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  284. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  285. 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
  286. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  287. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  288. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  289. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  290. Selectors
    https://golang.org/ref/spec#Selectors
  291. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  292. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  293. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  294. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  295. Part 21: Goroutines
    https://golangbot.com/goroutines/
  296. Part 22: Channels
    https://golangbot.com/channels/
  297. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  298. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  299. 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/
  300. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  301. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  302. Control Structures
    https://www.golang-book.com/books/intro/5
  303. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  304. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  305. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  306. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  307. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  308. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  309. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  310. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  311. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  312. Effective Go
    https://golang.org/doc/ef­fective_go.html
  313. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  314. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  315. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  316. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  317. Nils in Go
    https://www.doxsey.net/blog/nils-in-go

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.