Hlavní navigace

Programovací jazyk Go pro skalní céčkaře

19. 9. 2019
Doba čtení: 41 minut

Sdílet

Tato část seriálu o programovacím jazyce Go je určena především těm vývojářům, kteří na Go přechází z programovacího jazyka C a potřebují v Go nalézt ekvivalentní datové typy, programové konstrukce a funkce ze základní knihovny.

Obsah

1. Programovací jazyk Go pro skalní céčkaře

2. Základní rozdíly v syntaxi jazyků Go a C i ve struktuře programů

3. Klíčová slova programovacího jazyka Go

4. Deklarace proměnných

5. Základní datové typy

6. Podmínky

7. Zřetězené podmínky a jejich náhrada za switch

8. Programová smyčka typu while

9. Programová smyčka typu do-while

10. Počítaná programová smyčka typu for, více řídicích proměnných smyčky

11. Programová smyčka s podmínkou uprostřed

12. Konstrukce switch

13. Deklarace a volání funkcí

14. Návratové hodnoty funkcí

15. Funkce s proměnným počtem parametrů

16. Konstanty

17. Náhrada za výčtový typ

18. Obsah následující části seriálu

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

20. Odkazy na Internetu

1. Programovací jazyk Go pro skalní céčkaře

Poměrně často se uvádí, že na programovací jazyk Go přechází vývojáři, kteří používají programovací jazyk Python (což je téma popsané v knize [1]). To je na první pohled poněkud překvapivé zjištění, ovšem na druhou stranu se niky těchto dvou programovacích jazyků skutečně částečně překrývají, a to konkrétně u síťových a administrativních nástrojů. Přechod ke Go může pro nově vyvíjené projekty z této oblasti přinášet některé výhody [2] [3]. Ovšem existuje i velké množství vývojářů, kteří začínají Go používat i v těch oblastech, ve kterých se již po několik desetiletí používají programovací jazyky C a C++. Dnešní článek je zaměřen právě na céčkaře, protože se v něm snažím upozornit na ty vlastnosti jazyka Go, které mohou být překvapující nebo odlišné od toho, s čím se setkáme v céčku.

Poznámka: hned na úvod je nutné poznamenat, že Go není a ani nechce být plnohodnotnou náhradou programovacího jazyka C nebo dokonce C++. Jazykem s těmito ambicemi je spíše Rust, tedy za předpokladu, že bude dostatečně stabilizován a bude vydán jeho standard (ideálně v ISO nebo ANSI). Na celou problematiku se ale můžeme dívat přesně naopak: C/C++ se mnohdy používají i v těch situacích, kdy by bylo výhodnější nasadit Go.

V dalších kapitolách (i v navazující části tohoto seriálu) se budeme zabývat především tím, jaké existují ekvivalentní náhrady původních céčkových jazykových konstrukcí popř. funkcí ze standardní knihovny v programovacím jazyce Go. To mj. znamená, že se nebudeme soustředit na ty vlastnosti programovacího jazyka Go, které v klasickém C nemají přímou obdobu. Jedná se například o gorutiny a kanály. Pro ty sice existují v céčku příslušné knihovny (jimiž se taktéž budeme zabývat, ale až mnohem později), ovšem přímé porovnání s konstrukcemi jazyka Go nebude uvedeno.

Další informace o této problematice je možné najít na stránce GoForCPPProgrammers, stručné porovnání jednotlivých vlastností obou programovacích jazyků pak na stránce Hyperpolyglot: C, Go.

2. Základní rozdíly v syntaxi jazyků Go a C i ve struktuře programů

Nejprve se podívejme na to, jak se liší základní struktura programů vytvořených v programovacím jazyce Go a C. Nejjednodušší program, který po svém spuštění pouze nastaví návratový kód a ihned skončí, vypadá v C (konkrétně v ANSI C) takto:

int main(void)
{
    return 0;
}

V jazyku Go je struktura nepatrně odlišná. Především je nutné uvést jméno balíčku pomocí deklarace package. Dále se funkce main (jméno se nezměnilo) deklaruje s využitím klíčového slova func, tato funkce nemá žádné parametry (ani void – koncept void v Go ostatně vůbec neexistuje) a ani návratovou hodnotu; tudíž se nemusí použít ani příkaz return:

package main
 
func main() {
}

Nepatrně složitější program typu „Hello world“ již vyžaduje použití knihovních funkcí, jejichž hlavičky se načtou příkazem preprocesoru #include a o slinkování knihovny se musí postarat až linker. V céčku se může jednat o funkci puts, příkaz pro její zavolání povinně končí středníkem:

#include <stdio.h>
 
int main(void)
{
    puts("Hello world!");
    return 0;
}

V případě jazyka Go se namísto příkazu preprocesoru #include používá deklarace import zajišťující jak načtení funkcí, tak i jejich slinkování do výsledného spustitelného souboru. Jméno volané funkce se zapisuje včetně jména balíčku a externě viditelné funkce začínají velkým písmenem. Za příkazem pro volání funkce se nemusí zapisovat středník (a ani to prakticky nikdo nedělá):

package main
 
import "fmt"
 
func main() {
        fmt.Println("Hello world!")
}

3. Klíčová slova programovacího jazyka Go

V programovacím jazyce Go existuje celkem 25 klíčových slov, z nichž některé jsou odlišné od céčka. V praxi to znamená, že se při přepisu některých programů z C do Go může narazit na identifikátory, které je zapotřebí přejmenovat, protože není možné změnit význam klíčových slov (pravděpodobně se bude jednat o slova map a interface):

Kromě těchto klíčových slov se v Go setkáme s několika identifikátory, které mají pevný význam. Typicky se jedná o konstanty, v jednom případě o „automaticky měněnou konstantu“ a o pojmenování standardních datových typů. Jedná se o následující slova:

Identifikátor Typ Stručný popis
true konstanta pravdivostní hodnota
false konstanta pravdivostní hodnota
iota konstanta celočíselný automaticky zvyšovaný čítač
nil konstanta prázdná hodnota, prázdné rozhraní
   
bool datový typ logický/pravdivostní typ
byte datový typ alias pro typ uint8
int datový typ odpovídá buď typu int32 nebo int64
int8 datový typ osmibitové celé číslo se znaménkem
int16 datový typ šestnáctibitové celé číslo se znaménkem
int32 datový typ 32bitové celé číslo se znaménkem
int64 datový typ 64bitové celé číslo se znaménkem
uint datový typ odpovídá buď typu uint32 nebo uint64
uint8 datový typ osmibitové celé číslo bez znaménka
uint16 datový typ 16bitové celé číslo bez znaménka
uint32 datový typ 32bitové celé číslo bez znaménka
uint64 datový typ 64bitové celé číslo bez znaménka
float32 datový typ číslo s jednoduchou přesností podle IEEE 754
float64 datový typ číslo s dvojitou přesností podle IEEE 754
complex64 datový typ dvojice hodnot s jednoduchou přesností
complex128 datový typ dvojice hodnot s dvojitou přesností
error datový typ rozhraní s předpisem metody Error
rune datový typ alias pro typ int32
string datový typ
uintptr datový typ používáno pro uložení adresy (ukazatele)

Tyto identifikátory je sice možné použít i v jiném kontextu, ovšem silně nedoporučuji to dělat. Nicméně z hlediska překladače je následující program zcela korektní (z ostatních hledisek se jedná o programátorskou zvrhlost :-):

package main
 
func main() {
        true := 42
        false := "foobarbaz"
        println(true)
        println(false)
}

4. Deklarace proměnných

Poměrně velké rozdíly mezi oběma jazyky nalezneme při deklaraci proměnných, ať již se jedná o proměnné globální či lokální. V céčku existují poměrně sofistikovaná (a pochopitelně jednoznačná) pravidla, kterými se deklarace proměnných řídí, a to i v případě, že je typ proměnné netriviální – ukazatel na funkci, pole ukazatelů, ukazatel na ukazatel atd, I přesto, že jsou pravidla jednoznačná, nemusí být jejich zápis a čtení snadné:

int x;
unsigned char *y;
int a[10];
int *px;
int *py[10];
int (*pz)[10];
int *(*pw)[10];
float **m;

V programovacím jazyce Go se pravidla pro zápis deklarace proměnných do značné míry zjednodušila, a to takovým způsobem, aby byla deklarace (relativně) snadno čitelná zleva doprava (a to i v případě proměnných, jejichž hodnotou může být funkce):

var x int
var x2 int = 1
var a [10]int
var px *int
var py *[10]int
var f1 func()
var f2 func(int, int) int
Poznámka: použití klíčového slova var není samoúčelné, podobně jako použití klíčového slova func v deklaraci funkce. Díky tomu, že jakákoli deklarace vždy začíná klíčovým slovem, je možné zjednodušit vlastní parser programovacího jazyka Go a umožnit jeho snadnější zotavení z chyb.

Navíc se v jazyce Go objevuje i možnost deklarace proměnné s její inicializací a automatickým odvozením jejího typu. Pro tento účel se používá operátor :=, a to následujícím způsobem:

i := 10
f := 3.14
s := "foobar"
Poznámka: tato velmi užitečná jazyková konstrukce nemá v klasickém céčku obdobu, ovšem setkáme se s ní velice často.

5. Základní datové typy

Nabídka základních datových typů je jak v jazyku C, tak i v Go poměrně rozsáhlá a do značné míry shodná, ovšem v Go je (především u celočíselných datových typů) přesně definována bitová šířka většiny typů a tím pádem i rozsah povolených hodnot. V C tomu tak u obecných datových typů int, long, float atd. z dobrých důvodů není, a to mj. i z toho důvodu, že je tento jazyk používán na mnohdy dosti „obskurních“ platformách typu DSP se šířkou datové sběrnice a aritmeticko-logické jednotky 20 bitů (někdy navíc s 21bitovým mezivýsledkem).

V následující tabulce jsou uvedeny ekvivalentní či většinou ekvivalentní datové typy mezi C99 a Go (blíže viz https://en.cppreference.com/w/c/ty­pes/integer):

Typ v C99 Typ v Go
_Bool/bool bool
   
signed char int8 (ovšem klasické znaky jsou rune)
unsigned char uint8
   
int8_t int8
int16_t int16
int32_t int32
int64_t int64
intptr_t uintptr (viz níže)
   
uint8_t uint8
uint16_t uint16
uint32_t uint32
uint64_t uint64
uintptr_t uintptr
   
float float32 (platí na většině platforem)
double float64 (platí na většině platforem)
long double není podporováno (pokud se jedná o 80bitovou šířku)
   
float _Complex/float complex complex64
double _Complex/double complex complex128
long double _Complex/long double complex není podporováno

Poměrně často se v céčkovských programech setkáme s použitím operátoru sizeof:

#include <stdio.h>
 
int main(void)
{
    printf("sizeof char      = %lu byte(s)\n", sizeof(char));
    printf("sizeof short     = %lu byte(s)\n", sizeof(short));
    printf("sizeof int       = %lu byte(s)\n", sizeof(int));
    printf("sizeof long      = %lu byte(s)\n", sizeof(long));
    printf("sizeof long long = %lu byte(s)\n", sizeof(long long));
    printf("sizeof float     = %lu byte(s)\n", sizeof(float));
    printf("sizeof double    = %lu byte(s)\n", sizeof(double));
    return 0;
}

Přepis do Go je v tomto případě nepatrně složitější, neboť je nutné použít funkce z balíčku unsafe, kterým se ovšem nepředává datový typ, ale přímo hodnota určitého typu:

package main
 
import (
        "fmt"
        "unsafe"
)
 
func main() {
        fmt.Printf("sizeof int8       = %d byte(s)\n", unsafe.Sizeof(int8(0)))
        fmt.Printf("sizeof int16      = %d byte(s)\n", unsafe.Sizeof(int16(0)))
        fmt.Printf("sizeof int32      = %d byte(s)\n", unsafe.Sizeof(int32(0)))
        fmt.Printf("sizeof int64      = %d byte(s)\n", unsafe.Sizeof(int64(0)))
        fmt.Printf("sizeof int        = %d byte(s)\n", unsafe.Sizeof(int(0)))
        fmt.Printf("sizeof float32    = %d byte(s)\n", unsafe.Sizeof(float32(0)))
        fmt.Printf("sizeof float64    = %d byte(s)\n", unsafe.Sizeof(float64(0)))
        fmt.Printf("sizeof complex64  = %d byte(s)\n", unsafe.Sizeof(complex64(0)))
        fmt.Printf("sizeof complex128 = %d byte(s)\n", unsafe.Sizeof(complex128(0)))
        fmt.Printf("sizeof uintptr    = %d byte(s)\n", unsafe.Sizeof(uintptr(0)))
}
Poznámka: v praxi se ovšem s operátorem sizeof setkáme zejména v kódu pro alokaci paměti, která je v Go řešena odlišně. Dále se může jednat o operace s binárními soubory; zde se může použít výše zmíněný přístup s unsafe.Sizeof.

6. Podmínky

V této kapitole se zaměříme na popis základních rozdílů mezi programovými konstrukcemi určenými pro řízení běhu programu. V první řadě se pochopitelně jedná o podmínky a s nimi souvisejícím rozvětvením běhu programu. V programovacím jazyku C máme k dispozici podmíněnou konstrukci s jednou větví if i plné rozvětvení realizované konstrukcí typu if-else. Jednotlivé větve mohou být tvořeny jedním příkazem popř. blokem příkazů uzavřených do složených závorek. Samotná testovaná podmínka, což je většinou celočíselný výraz, musí být vždy umístěna do kulatých závorek:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
 
    if (x > 0) {
        puts("x is positive number");
    }
 
    return 0;
}

alternativně též bez použití bloku:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
 
    if (x > 0)
        puts("x is positive number");
 
    return 0;
}

Naproti tomu v programovacím jazyku Go platí nepatrně odlišná pravidla. Především se výraz představující podmínku musí vyhodnotit na pravdivostní hodnotu true nebo false. Dále se tento výraz nemusí uzavírat do kulatých závorek. Samotné větve jsou vždy tvořeny bloky, tj. nemusíme se bát, že se přidáním dalšího příkazu do původně jednopříkazové větvě celá struktura programu změní (chyba typu Apple GOTO fail):

package main
 
import "fmt"
 
func main() {
        x := 10
 
        if x > 0 {
                fmt.Println("x is positive number")
        }
}

Plné rozvětvení typu if-else je v céčku realizováno takto:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
 
    if (x > 0) {
        puts("x is positive number");
    }
    else {
        puts("x is negative number or zero");
    }
 
    return 0;
}

Popř. bez bloků:

#include <stdio.h>
 
int main(void)
{
    int x = 10;
 
    if (x > 0)
        puts("x is positive number");
    else
        puts("x is negative number or zero");
 
    return 0;
}

V jazyku Go jsou bloky povinné a navíc je vyžadováno, aby klíčové slovo else leželo na stejném řádku, jako pravá uzavírací závorka:

package main
 
import "fmt"
 
func main() {
        x := 10
 
        if x > 0 {
                fmt.Println("x is positive number")
        } else {
                fmt.Println("x is negative number or zero")
        }
}

Kromě toho lze v programovacím jazyku Go deklarovat proměnné, které jsou lokální pouze v rámci konstrukce if popř. úplného rozvětvení if-else. Mimo tuto konstrukci není proměnná viditelná:

if result, err := compute(x,y); err != nil {
        ...
        ...
        ...
} else {
        ...
        ...
        ...
}

V tomto příkladu jsou deklarovány dvě proměnné nazvané result a err, které jsou viditelné pouze uvnitř rozhodovací konstrukce. Na základě hodnoty proměnné err se aplikace rozhoduje, zda vstoupit do větve if nebo naopak do větve else. Pokud bychom nevyžadovali použití lokálně viditelných proměnných, můžeme samozřejmě psát:

result, err := compute(x,y)
 
if err != nil {
        ...
        ...
        ...
} else {
        ...
        ...
        ...
}
Poznámka: minimálně pro účely detekce chyb je použití lokálně viditelných proměnných poměrně často používáno, i když se zejména zpočátku nemusí jednat o nejčitelnější jazykovou konstrukci.

7. Zřetězené podmínky a jejich náhrada za switch

V programovacím jazyku C je možné podmínky zřetězit, popř. vnořit. Podívejme se na jednoduchý demonstrační příklad, v němž se provádí test, jestli je obsahem celočíselné proměnné kladné číslo, číslo záporné nebo nula:

#include <stdio.h>
 
int main(void)
{
    int x = 0;
 
    if (x > 0) {
        puts("x is positive number");
    }
    else if (x == 0) {
        puts("x is zero");
    }
    else {
        puts("x is negative number");
    }
 
    return 0;
}

Přepis do Go je v tomto případě přímočarý, samozřejmě s tím rozdílem, že se podmínky nemusí zapisovat do kulatých závorek a příkazy se neukončují středníkem:

package main
 
import "fmt"
 
func main() {
        x := 10
 
        if x > 0 {
                fmt.Println("x is positive number")
        } else if x == 0 {
                fmt.Println("x is zero")
        } else {
                fmt.Println("x is negative number")
        }
}

Tento příklad lze přepsat takovým způsobem, že se namísto zřetězení konstrukcí typu if-else použije konstrukce typu switch. V programovacím jazyku Go je totiž možné do jednotlivých větví case zapisovat plnohodnotné podmínky a v tomto případě se za samotné klíčové slovo switch nezapisuje žádný výraz. Jednotlivé větve se neukončují slovem break:

package main
 
import "fmt"
 
func main() {
        x := 10
 
        switch {
        case x > 0:
                fmt.Println("x is positive number")
        case x == 0:
                fmt.Println("x is zero")
        default:
                fmt.Println("x is negative number")
        }
}
Poznámka: přednost tohoto způsobu zápisu oceníme ve chvíli, kdy je řetězec if-else-if-else-if… delší.

8. Programová smyčka typu while

V programovacím jazyku C existují tři typy programových smyček: while, do-while a počítaná smyčka for. Nejprve si ukažme nejjednodušší způsob použití smyčky while, v níž se podmínka testuje na začátku každé iterace, tedy před vstupem do smyčky:

#include <stdio.h>
 
int main(void)
{
    int x = 1;
 
    while (x <= 10) {
        printf("%d\n", x);
        x++;
    }
 
    return 0;
}

V programovacím jazyce Go je nutné tento typ smyčky realizovat s využitím klíčového slova for, za které se napíše pouze podmínka. Ta je opět testována před vstupem do těla smyčky a tudíž se tento typ programové smyčky nemusí provést ani jednou:

package main
 
import "fmt"
 
func main() {
        x := 1
 
        for x <= 10 {
                fmt.Printf("%d\n", x)
                x++
        }
}
Poznámka: často se v céčkových programech můžeme setkat s tím, že se přímo v podmínce zvyšuje či naopak snižuje hodnota testované proměnné o jedničku pomocí operátorů ++ a --:
#include <stdio.h>
 
int main(void)
{
    int x = 0;
 
    while (x++ < 10) {
        printf("%d\n", x);
    }
 
    return 0;
}
Tento zápis ovšem v Go nemá přímou obdobu, protože ++ a – je nutné zapisovat jako samostatný příkaz a nikoli ve složitějším výrazu jako operátor.

9. Programová smyčka typu do-while

Druhým typem programové smyčky v programovacím jazyku C je smyčka typu do-while, v níž je test, zda provést či neprovést další iteraci, vyhodnocen až na konci každého cyklu:

#include <stdio.h>
 
int main(void)
{
    int x = 1;
 
    do {
        printf("%d\n", x);
        x++;
    } while (x <= 10);
 
    return 0;
}

V jazyku Go v tomto případě budeme muset použít pomocnou proměnnou a použít plnou podobu programové smyčky for s inicializačním výrazem, podmínkou a výrazem spuštěným na konci těla smyčky:

package main
 
import "fmt"
 
func main() {
        x := 1
 
        for cond := true; cond; cond = x <= 10 {
                fmt.Printf("%d\n", x)
                x++
        }
}

V tomto příkladu byla vytvořena lokální proměnná cond, která je na konci každé iterace znovu nastavena na pravdivostní hodnotu vyjádřenou podmínkou. Na základě této hodnoty je smyčka buď ukončena nebo je provedena další iterace.

Poznámka: ve skutečnosti je poměr frekvence použití smyček while ku do-while větší než 10:1, takže se výše uvedený (a nepěkný trik) nemusí používat příliš často.

10. Počítaná programová smyčka typu for, více řídicích proměnných smyčky

V programovacím jazyku C se velmi často setkáme s počítanou programovou smyčkou, v níž je použita jedna řídicí proměnná fungující jako počitadlo smyčky:

#include <stdio.h>
 
int main(void)
{
    int x;
 
    for (x=1; x <= 10; x++) {
        printf("%d\n", x);
    }
 
    return 0;
}

Popř. v C99:

#include <stdio.h>
 
int main(void)
{
    for (int x=1; x <= 10; x++) {
        printf("%d\n", x);
    }
 
    return 0;
}

Přepis do jazyka Go je v tomto případě přímočarý a můžeme (podobně jako v C99) použít lokální proměnnou jako počitadlo (proměnná bude viditelná a platná jen v rámci smyčky). Povšimněte si, že se všechny tři výrazy za klíčovým slovem for neuzavírají do závorek:

package main
 
import "fmt"
 
func main() {
        for x := 1; x <= 10; x++ {
                fmt.Printf("%d\n", x)
        }
}

Samozřejmě není nutné, aby se počitadlo smyčky zvyšovalo či snižovalo o jedničku, ale můžeme použít složitější výpočet:

#include <stdio.h>
 
int main(void)
{
    int x;
 
    for (x=1; x <= 10000; x<<=1) {
        printf("%d\n", x);
    }
 
    return 0;
}

Přepis do Go je i zde přímočarý:

package main
 
import "fmt"
 
func main() {
        for x := 1; x <= 10000; x<<=1 {
                fmt.Printf("%d\n", x)
        }
}

V posledním příkladu jsou použity dvě proměnné, z nichž jedna se zvyšuje o jedničku (jako běžné počitadlo) a druhá se s každou iterací zdvojnásobí:

#include <stdio.h>
 
int main(void)
{
    int i,x;
 
    for (i=0, x=1; i <= 10; i++, x<<=1) {
        printf("2^%d = %d\n", i, x);
    }
 
    return 0;
}

Tento příklad není možné v Go zapsat stejným způsobem, protože Go nepodporuje operátor čárky. Ovšem můžeme zde použít malého triku – vícenásobného přiřazení, a to jak v prvním výrazu (inicializace obou proměnných), tak i v iteračním výrazu:

package main
 
import "fmt"
 
func main() {
        for i, x := 0, 1; x <= 10000; i, x = i+1, x<<1 {
                fmt.Printf("%d\n", x)
        }
}
Poznámka: povšimněte si, že i++ není možné použít, a to z toho důvodu, že se v Go nejedná o operátor, ale o samostatně stojící příkaz.

11. Programová smyčka s podmínkou uprostřed

Programovou smyčku s podmínkou vyhodnocovanou uprostřed těla smyčky lze realizovat různým způsobem. V céčku se často můžeme setkat s následujícím postupem, v němž je smyčka na základě podmínky ukončena příkazem break:

#include <stdio.h>
 
int main(void)
{
    int x = 1;
 
    while (1) {
        printf("%d\n", x);
        x++;
        if (x > 10) break;
    }
 
    return 0;
}

Prakticky stejným způsobem, jen s nepatrnými rozdíly v syntaxi, se může provést zápis v jazyce Go. Povšimněte si, že v tomto případě není za klíčovým slovem for uvedena žádná podmínka:

package main
 
import "fmt"
 
func main() {
        x := 1
 
        for {
                fmt.Printf("%d\n", x)
                x++
                if x > 10 {
                        break
                }
        }
}

Pokud ovšem preferujete, aby byla proměnná x lokální v rámci smyčky, musí se podmínka zapsat, ovšem postačuje použít hodnotu true, která se vyhodnotí opět na true. Poslední výraz za středníkem lze zcela vynechat, ovšem středník je zde nutné ponechat:

package main
 
import "fmt"
 
func main() {
        for x := 1; true;  {
                fmt.Printf("%d\n", x)
                x++
                if x > 10 {
                        break
                }
        }
}

12. Konstrukce switch

Ještě větší rozdíly mezi oběma programovacími jazyky nalezneme v rozhodovací konstrukci switch. Ta se ve standardním cečku používá pro rozeskok na základě hodnoty celočíselného výrazu, jehož výsledek je postupně porovnáván s celočíselnými konstantami. Pokud mají být jednotlivé větve rozeskoku odděleny, musí být každá větev explicitně ukončena příkazem break popř. příkazem return (některé lintery ovšem vyžadují zápis break i za return což je přinejmenším nadbytečné). V následujícím příkladu využíváme toho, že bez ukončení větve příkazy break/return je řízení běhu programu automaticky předáno do následující větve, takže se například všechna sudá čísla v rozsahu od 0 do 9 zpracují jediným společným příkazem:

#include <stdio.h>
 
const char *classify(int x) {
        switch (x) {
        case 0:
                return "nula";
        case 2:
        case 4:
        case 6:
        case 8:
                return "sudé číslo";
        case 1:
        case 3:
        case 5:
        case 7:
        case 9:
                return "liché číslo";
        default:
                return "?";
        }
}
 
int main(void) {
    int x;
    for (x = 0; x <= 10; x++) {
        printf("%d: %s\n", x, classify(x));
    }
    return 0;
}

V programovacím jazyku Go se příkaz break v konstrukci switch nepoužívá, protože je proveden skutečný rozeskok. Pokud je nutné, aby se pro dvě či více podmínek vykonala společná část kódu, musí se použít klíčové slovo fallthrough, ovšem v reálných programech se s ním příliš často nesetkáme. Nejvíce rozdílů ovšem nalezneme u podmínek zapisovaných za klíčovým slovem case; nemusí se totiž jednat o pouhé celočíselné konstanty, ale o složitější výrazy, včetně seznamu (přesněji řečeno výčtu) hodnot:

package main
 
import "fmt"
 
func classify(x int) string {
        switch x {
        case 0:
                return "nula"
        case 2, 4, 6, 8:
                return "sudé číslo"
        case 1, 3, 5, 7, 9:
                return "liché číslo"
        default:
                return "?"
        }
}
 
func main() {
        for x := 0; x <= 10; x++ {
                fmt.Printf("%d: %s\n", x, classify(x))
        }
}

Otrocký přepis předchozího céčkového programu do programovacího jazyka Go bude delší a méně čitelný:

package main
 
import "fmt"
 
func classify(x int) string {
        switch x {
        case 0:
                return "nula"
        case 2:
                fallthrough
        case 4:
                fallthrough
        case 6:
                fallthrough
        case 8:
                return "sudé číslo"
        case 1:
                fallthrough
        case 3:
                fallthrough
        case 5:
                fallthrough
        case 7:
                fallthrough
        case 9:
                return "liché číslo"
        default:
                return "?"
        }
}
 
func main() {
        for x := 0; x <= 10; x++ {
                fmt.Printf("%d: %s\n", x, classify(x))
        }
}

13. Deklarace a volání funkcí

Každý céčkový program obsahuje deklaraci funkcí a jejich volání. Jen pro úplnost si uveďme, jak taková deklarace vypadá v případě funkce bez parametrů a bez návratové hodnoty:

#include <stdio.h>
 
void printHello(void) {
    puts("Hello world!");
}
 
int main(void) {
    printHello();
    return 0;
}

Přepis do Go bude v tomto případě snadný, protože použijeme klíčové slovo func, funkce bez parametrů obsahuje za svým jménem prázdné závorky (což má v C odlišný význam!) a případný návratový typ/typy je uveden až za těmito závorkami:

package main
 
import "fmt"
 
func printHello() {
        fmt.Println("Hello world!")
}
 
func main() {
        printHello()
}
Poznámka: otevírací složená závorka by měla začínat na stejném řádku, jako samotná hlavička funkce. V případě jazyka C to není vyžadováno.

Příklad funkce s parametrem zapsané v C:

#include <stdio.h>
 
void printHello(const char *message) {
    puts(message);
}
 
int main(void) {
    printHello("Hello world!");
    return 0;
}

Ekvivalentní zápis v Go:

package main
 
import "fmt"
 
func printMessage(message string) {
        fmt.Println(message)
}
 
func main() {
        printMessage("Hello world!")
}

14. Návratové hodnoty funkcí

Funkce getMessage s návratovou hodnotou zapsaná v C:

#include <stdio.h>
 
const char *getMessage(void) {
    return "Hello world!";
}
 
void printMessage(const char *message) {
    puts(message);
}
 
int main(void) {
    printMessage(getMessage());
    return 0;
}

Přepis do Go; v tomto případě se návratový typ zapisuje mezi uzavírací kulatou závorku a otevírací závorku s tělem funkce:

package main
 
import "fmt"
 
func getMessage() string {
        return "Hello world!"
}
 
func printMessage(message string) {
        fmt.Println(message)
}
 
func main() {
        printMessage(getMessage())
}
Poznámka: ve skutečnosti mohou v Go funkce vracet více hodnot, ovšem tato technika nemá v klasickém C ekvivalent (snad jen předávání parametrů odkazem), takže by v tomto případě neměly nastat problémy.

15. Funkce s proměnným počtem parametrů

V některých aplikacích se setkáme s funkcemi s proměnným počtem parametrů. Skutečný počet parametrů musí být volané funkci nějakým způsobem sdělen, například předáním počtu ve zvláštním parametru, použitím formátovacího řetězce či jeho obdoby (printf) nebo například tím, že poslední parametr bude mít určitou předem známou hodnotu (0, –1, NULL atd.). Ukažme si první popsaný způsob, tj. explicitní předání počtu parametrů u funkcí f2 a f3:

#include <stdio.h>
#include <stdarg.h>
 
void f1(const char *msg) {
    printf("%s\n", msg);
}
 
void f2(int count, ...) {
    int i;
    va_list args;
    va_start(args, count);
 
    for (i = 0; i < count; i++) {
        char *msg = va_arg(args, char *);
        printf("%s ", msg);
    }
    putchar('\n');
    va_end(args);
}
 
void f3(char *prefix, int count, ...) {
    int i;
    va_list args;
 
    printf("%s ", prefix);
    va_start(args, count);
 
    for (i = 0; i < count; i++) {
        char *msg = va_arg(args, char *);
        printf("%s ", msg);
    }
    putchar('\n');
    va_end(args);
}
 
int main(void) {
    f1("Hello");
    f2(3, "Hello", "world", "!");
    f3("Message:", 4, "Hello", "world", "again", "!");
    return 0;
}

Můžeme vidět, že celé zpracování proměnného počtu parametrů je řešeno knihovními funkcemi va_start, va_arg a va_end.

V případě programovacího jazyka Go se používá poněkud odlišný přístup, kdy je určen typ parametrů, ovšem jejich počet se získá automaticky při průchodu všemi parametry:

package main
 
import "fmt"
 
func f1(msg string) {
        fmt.Printf("%s\n", msg)
}
 
func f2(parts ...string) {
        for _, val := range parts {
                fmt.Printf("%s ", val)
        }
        fmt.Println()
}
 
func f3(prefix string, parts ...string) {
        fmt.Printf("%s ", prefix)
        for _, val := range parts {
                fmt.Printf("%s ", val)
        }
        fmt.Println()
}
 
func main() {
        f1("Hello")
        f2("Hello", "world", "!")
        f3("Message:", "Hello", "world", "again", "!")
}
Poznámka: pokud je zapotřebí, aby parametry mohly být jakéhokoli typu, lze použít prázdné rozhraní (interface), které automaticky implementují všechny datové typy. Ovšem obecně se nejedná o příliš dobrý způsob a použití prázdného rozhraní je chápáno za berličku obcházející typový systém jazyka.

16. Konstanty

V programovacím jazyku C lze konstanty vytvořit buď s využitím preprocesoru (#define), což zajistí textovou substituci jména konstanty za její obsah, nebo s využitím klíčového slova const společně s deklarací a inicializací proměnné. V programovacím jazyku Go lze konstanty taktéž vytvářet s využitím klíčového slova const, které zde ovšem nepředstavuje modifikátor, ale začátek deklarace. Typ konstanty je buď odvozen automaticky z přiřazované hodnoty (může se jednat i o konstantní výraz), nebo je alternativně možné typ konstanty uvést explicitně:

package main
 
import "fmt"
 
const Pi float64 = 3.1415927
const E = 2.71828
 
const z0 int = 0
const z1 = 0
 
const z2 = z0 + z1
 
func main() {
        fmt.Printf("Pi = %f\n", Pi)
        fmt.Printf("e = %f\n", E)

        fmt.Printf("z0 = %d\n", z0)
        fmt.Printf("z1 = %d\n", z1)

        fmt.Printf("z2 = %d\n", z2)
}

To, že const v Go znamená začátek deklarace a ne „pouhý“ modifikátor datového typu, je zřejmé z následujícího příkladu, v němž jsou konstanty vytvořeny v jediném bloku:

package main
 
import "fmt"
 
const (
        Pi float64 = 3.1415927
        E          = 2.71828
 
        z0 int = 0
        z1     = 0
        z2     = z0 + z1
)
 
func main() {
        fmt.Printf("Pi = %f\n", Pi)
        fmt.Printf("e = %f\n", E)
 
        fmt.Printf("z0 = %d\n", z0)
        fmt.Printf("z1 = %d\n", z1)
 
        fmt.Printf("z2 = %d\n", z2)
}

17. Náhrada za výčtový typ

V jazyku C mají programátoři k dispozici datový typ výčet (enum), v němž je jednotlivým položkám automaticky či manuálně přiřazena nějaká celočíselná hodnota (ve výchozím nastavení index položky):

#include <stdio.h>
 
enum {
    Pondeli,
    Utery,
    Streda,
    Ctvrtek,
    Patek,
    Sobota,
    Nedele
};
 
int main(void) {
    printf("%d\n", Pondeli);
    printf("%d\n", Streda);
    printf("%d\n", Patek);
    return 0;
}

Tuto možnost sice v Go přímo nemáme, ovšem existuje částečně ekvivalentní řešení postavené na použití „automaticky měněné konstanty“ iota, kterou lze považovat za počitadlo položky:

UX DAy - tip 2

package main
 
import "fmt"
 
const (
        Pondeli = iota
        Utery
        Streda
        Ctvrtek
        Patek
        Sobota
        Nedele
)
 
func main() {
        fmt.Printf("%d\n", Pondeli)
        fmt.Printf("%d\n", Streda)
        fmt.Printf("%d\n", Patek)
}
Poznámka: přiřazení = iota je možné použít jen u prvního prvku, dále je doplněno překladačem automaticky. Nebo pochopitelně můžeme provést explicitní přiřazení pro všechny konstanty.

18. Obsah následující části seriálu

V následující části tohoto seriálu se opět zaměříme na porovnání možností jazyků C a Go. Popíšeme si tato témata:

  1. Aritmetické výpočty, knihovna s matematickými funkcemi
  2. Zpracování řetězců
  3. Funkce pro práci s řetězci
  4. Datum a čas
  5. Práce se soubory
  6. Uživatelsky definované datové typy
  7. Zpracování chyb (praktické ukázky a porovnání)
  8. Interakce aplikace s okolním systémem

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

# Příklad Cesta
1 01_empty_main.c https://github.com/tisnik/go-root/blob/master/article34/01_em­pty_main.c
1 01_empty_main.go https://github.com/tisnik/go-root/blob/master/article34/01_em­pty_main.go
     
2 02_hello_world.c https://github.com/tisnik/go-root/blob/master/article34/02_he­llo_world.c
2 02_hello_world.go https://github.com/tisnik/go-root/blob/master/article34/02_he­llo_world.go
     
3 03_data_types.c https://github.com/tisnik/go-root/blob/master/article34/03_da­ta_types.c
3 03_data_types.go https://github.com/tisnik/go-root/blob/master/article34/03_da­ta_types.go
     
4 04_if_then.c https://github.com/tisnik/go-root/blob/master/article34/04_if_then­.c
4 04_if_then.go https://github.com/tisnik/go-root/blob/master/article34/04_if_then­.go
     
5 05_if_then_else.c https://github.com/tisnik/go-root/blob/master/article34/05_if_then_el­se.c
5 05_if_then_else.go https://github.com/tisnik/go-root/blob/master/article34/05_if_then_el­se.go
     
6 06_better_approach.go https://github.com/tisnik/go-root/blob/master/article34/06_bet­ter_approach.go
6 06_nested_if.c https://github.com/tisnik/go-root/blob/master/article34/06_nes­ted_if.c
6 06_nested_if.go https://github.com/tisnik/go-root/blob/master/article34/06_nes­ted_if.go
     
7 07_while_loop.c https://github.com/tisnik/go-root/blob/master/article34/07_whi­le_loop.c
7 07_while_loop.go https://github.com/tisnik/go-root/blob/master/article34/07_whi­le_loop.go
     
8 08_while_loop.c https://github.com/tisnik/go-root/blob/master/article34/08_whi­le_loop.c
     
9 09_do_while_loop.c https://github.com/tisnik/go-root/blob/master/article34/09_do_whi­le_loop.c
9 09_do_while_loop.go https://github.com/tisnik/go-root/blob/master/article34/09_do_whi­le_loop.go
     
10 10_for_loop.c https://github.com/tisnik/go-root/blob/master/article34/10_for_lo­op.c
10 10_for_loop.go https://github.com/tisnik/go-root/blob/master/article34/10_for_lo­op.go
     
11 11_for_loop.c https://github.com/tisnik/go-root/blob/master/article34/11_for_lo­op.c
11 11_for_loop.go https://github.com/tisnik/go-root/blob/master/article34/11_for_lo­op.go
     
12 12_for_loop.c https://github.com/tisnik/go-root/blob/master/article34/12_for_lo­op.c
12 12_for_loop.go https://github.com/tisnik/go-root/blob/master/article34/12_for_lo­op.go
     
13 13_break_in_loop_B.go https://github.com/tisnik/go-root/blob/master/article34/13_bre­ak_in_loop_B.go
13 13_break_in_loop.c https://github.com/tisnik/go-root/blob/master/article34/13_bre­ak_in_loop.c
13 13_break_in_loop.go https://github.com/tisnik/go-root/blob/master/article34/13_bre­ak_in_loop.go
     
14 14_switch.c https://github.com/tisnik/go-root/blob/master/article34/14_swit­ch.c
14 14_switch.go https://github.com/tisnik/go-root/blob/master/article34/14_swit­ch.go
     
15 15_simple_function.c https://github.com/tisnik/go-root/blob/master/article34/15_sim­ple_function.c
15 15_simple_function.go https://github.com/tisnik/go-root/blob/master/article34/15_sim­ple_function.go
     
16 16_function_with_params.c https://github.com/tisnik/go-root/blob/master/article34/16_fun­ction_with_params.c
16 16_function_with_params.go https://github.com/tisnik/go-root/blob/master/article34/16_fun­ction_with_params.go
     
17 17_return_statement.c https://github.com/tisnik/go-root/blob/master/article34/17_re­turn_statement.c
17 17_return_statement.go https://github.com/tisnik/go-root/blob/master/article34/17_re­turn_statement.go
     
18 18_variadic_function.c https://github.com/tisnik/go-root/blob/master/article34/18_va­riadic_function.c
18 18_variadic_function.go https://github.com/tisnik/go-root/blob/master/article34/18_va­riadic_function.go
     
19 19_constants.go https://github.com/tisnik/go-root/blob/master/article34/19_con­stants.go
     
20 20_constants.go https://github.com/tisnik/go-root/blob/master/article34/20_con­stants.go
     
21 21_enum.c https://github.com/tisnik/go-root/blob/master/article34/21_enum.c
21 21_iota.go https://github.com/tisnik/go-root/blob/master/article34/21_i­ota.go

20. Odkazy na Internetu

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

Byl pro vás článek přínosný?