Tworzenie projektu w Go

W tym przewodniku pokażę Ci jak stworzyć środowisko do pracy nad dowolnym projektem. Jako przykład zaimplementujemy bardzo prosty program przetwarzający dokumenty zapisane w języku znaczników Markdown na fragmenty HTMLa

Ten artykuł ma na celu zaprezentowanie:

  • strukturę katalogów w projekcie
  • konfigurację systemu
  • narzędzie go build do kompilacji kodu i go get do ściągania zewnętrznych bibliotek
  • współpracę z zewnętrznymi bibliotekami

Potrzebne składniki

Praca z Go nie wymaga wielu narzędzi. Nam wystarczą:

Edytor tekstowy. Wybierz jaki chcesz, instrukcje tu podane nie będą zależały od niego.

Konsola. Są ludzie, którzy nie lubią używać konsol. Moim skromnym zdaniem, to tylko obawa przed czymś czego nie znamy. Znajomość obsługi konsoli znacząco zwiększy twoją wydajność jako programisty, a dodatkowo umożliwi Ci przejście przez ten tutorial :-)

Kompilator Go. Instrukcje jak zaintalować kompilator (a z nim kilka bardzo użytecznych narzędzi), znajdziesz tu

Drobna uwaga na koniec: instrukcje konsolowe będą właściwe dla systemów linux, ale wszystkie powinny mniej więcej działać także na windowsie (jeśli będą problemy proponuję zainstalować zestaw narzędzi MinGW)

Krok pierwszy - tworzymy katalog projektu

Projekty Go składają się najczęściej z:

  • właściwego kodu programu
  • zewnętrznych bibliotek
  • skompilowanych, gotowych do uruchomienia plików wykonywalnych

Żeby nie utrudniać już na wstępie zakładamy, że chcemy trzymać wszystko razem w katalogu workspace (nazwa jest dowolna). Załóż taki katalog w dowolnym miejscu na dysku, a w nim trzy dodatkowe katalogi src i libs i bin. W katalogu libs stwórzmy również podkatalogi src i bin.

mkdir workspace/bin
mkdir workspace/libs
mkdir workspace/libs/bin
mkdir workspace/libs/src
mkdir workspace/src

Katalog workspace będę nazywał $PROJECT_DIR.

Konfigurujemy środowisko

Aby pracować z narzędziami go musimy skonfigurować zmienną środowiskową GOPATH, dzięki której komenda go będzie wiedziała, gdzie ma szukać plików. Może ona wskazywać na wiele katalogów, ale nam wystarczą dwa workspace i workspace/lib. W linuksie robi się to jednym poleceniem:

export GOPATH=$PROJECT_DIR/libs:$PROJECT_DIR

Ścieżkę $PROJECT_DIR/libs umieść na początku zmiennej GOPATH, dzięki temu pakiety ściągane z sieci nie będą się plątały między lokalnymi.

Przetestujmy czy to działa. Stworz prosty program wypisujący na ekran "witaj świecie" - tj. skopiuj listing poniżej do pliku $PROJECT_DIR/src/hello/main.go.

package main
import "fmt"

func main() {
    fmt.Println("Witaj świecie!")
}

Teraz wystarczy wpisać w konsoli:

go build hello
./hello

Polecenie go build hello będzie szukało katalogu hello by skompilować pakiet hello. W przypadku, gdy w tym katalogu znajdzie main, domyśli się, że to jest program i skompiluje go do pliku hello. Jeśli test wyszedł pomyślnie to możemy przejść do ciekawszych zagadnień.

Szukanie i instalacja odpowiedniej biblioteki

W bibliotece standardowej nie ma pakietu, który przetwarzałby znaczniki markdown na html, trzeba taki pakiet albo napisać (złe rozwiązanie), albo znaleźć na sieci. Jeśli samo odpytanie wyszukiwarki (np. google) o interesujący pakiet nie zwraca nic ciekawego to można jeszcze spróbować:

Mi się udało znaleźć taki pakiet. Został on udostępniony na githubie. Jeśli zdecydujemy się na pakiet udostępniony za pośrednictwem githuba, bitbucketa czy code.google.com, to jest duża szansa, że możemy go dołączyć do swojej puli pakietów prostym poleceniem go get. Np.:

go get github.com/russross/blackfriday

Jeśli ścieżki $GOPATH zostały ustawione zgodnie z moim zaleceniem, to źródła i binarna postać biblioteki znajdą się w katalogach (odpowiednio) $PROJECT_DIR/libs/src/ i $PROJECT_DIR/libs/pkg/

Piszemy program właściwy

Prosty program w Go składa się z trzech elementów:

  • Definicja nazwy pakietu. W przypadku pakietu uruchamiającego program musi to być "main", taką konwencję przyjęli twórcy języka. Inne pakiety możemy nazywać niemal dowolnie, jednak pakiet uruchomieniowy zawsze ma nazywać się "main"

  • Import wymaganych pakietów. "Wymagane" oznacza, że nie jest dopuszczalna sytuacja w której importujemy pakiet, którego nie używamy - program się nie skompiluje gdy zostawimy jakieś "śmieciowe" pakiety. Ścieżki pakietów ujmujemy w cudzysłowia.

  • Deklaracja funkcji main. Przetwarzanie programu rozpoczyna i kończy się w tej funkcji. Funkcja main nie przyjmuje i nie zwraca żadnych wartości.

A oto nasz konwerter:

package main

import (
    bfri "github.com/russross/blackfriday"
    "io/ioutil"
    "os"
    "fmt"
)

func main() {
    arguments := os.Args
    if len(arguments) < 2 {
        fmt.Println("Podaj nazwę pliku który chcesz wczytać")
        os.Exit(1)
    }
    filename := arguments[1]
    fcontents, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Printf("Błąd wczytywania pliku %v \n", filename)
        os.Exit(1)
    }

    os.Stdout.Write(bfri.MarkdownBasic(fcontents))
}

Aby dowiedzieć się więcej o instrukcji import polecam ten artykuł

Umieść powyższy kod w katalogu $PROJECT_DIR/src/mdconv/main.go.

Kompilacja

Kompilujemy program za pomocą następującej komendy:

go build mdconv

W katalogu w którym ją wykonasz pojawi się plik mdconv. Zapisz poniższy dokument testowy do pliku test.md:

# Hello world #
Testowy dokument

    z kodem

Po wywołaniu ./mdconv test.md powinieneś ujrzeć następujący wydruk:

<h1>Hello world</h1>

<p>Testowy dokument</p>

<pre><code>z kodem
</code></pre>