Go dla początkujących - Część 5: Pakiety i importy

2/1/2025 Kurs Go

Mateusz Kędziora

image

Witaj w kolejnym wpisie z serii o języku Go! Dzisiaj zajmiemy się tematem, który jest fundamentem każdego większego projektu – pakiety i importy. Bez tego mechanizmu tworzenie rozbudowanych programów byłoby chaotyczne i trudne. Pakiety pozwalają nam na modularne dzielenie kodu, a importy umożliwiają korzystanie z kodu napisanego przez innych. Zaczynamy!

Co to są pakiety i dlaczego są ważne?

Wyobraź sobie, że budujesz dom. Nie wrzucasz wszystkich cegieł, desek i gwoździ w jedną wielką kupę, prawda? Zamiast tego, sortujesz materiały według ich przeznaczenia – cegły na ściany, drewno na dach, itp. Podobnie jest z kodem. Pakiet (package) to sposób na logiczne grupowanie powiązanych funkcji, zmiennych i typów. To jakbyś miał oddzielne “pokoje” w swoim projekcie, każdy z własnym zestawem narzędzi.

Dzięki pakietom:

  • Kod jest bardziej zorganizowany: Łatwiej odnaleźć potrzebne elementy i unikać chaosu.
  • Można ponownie wykorzystywać kod: Pakiety z dobrze napisanym kodem możesz wykorzystać w różnych miejscach projektu, a nawet w innych projektach.
  • Praca zespołowa staje się łatwiejsza: Różne osoby mogą pracować nad różnymi pakietami bez wchodzenia sobie w drogę.
  • Kod jest bardziej czytelny: Łatwiej zrozumieć, co robi dany fragment kodu, kiedy jest uporządkowany.

W Go, każdy plik .go musi należeć do jakiegoś pakietu. Deklaruje się to na początku pliku, za pomocą słowa kluczowego package.

Importy: Korzystanie z kodu innych

Kiedy już podzielimy nasz kod na pakiety, potrzebujemy sposobu, żeby z tych pakietów korzystać. Tutaj z pomocą przychodzą importy. Importy pozwalają na używanie kodu z innych pakietów w naszym aktualnym kodzie. To tak jakbyśmy mogli w naszym domu skorzystać z narzędzi z sąsiedniego domu – oczywiście za ich zgodą (w tym przypadku zgoda jest implicitowana poprzez eksport).

Go ma wiele wbudowanych pakietów w tzw. bibliotece standardowej. Dostępnych jest również wiele pakietów zewnętrznych, które udostępniają funkcjonalności rozszerzające możliwości języka.

Biblioteka Standardowa Go: Skarbnica gotowych rozwiązań

Biblioteka standardowa Go to zestaw pakietów, które są dołączone do każdej instalacji języka. Znajdziesz w niej pakiety do obsługi plików, sieci, operacji matematycznych, tekstu i wielu innych zadań.

Przykłady popularnych pakietów:

  • fmt: Służy do formatowania wejścia/wyjścia, np. drukowania na ekranie.
  • math: Zawiera funkcje matematyczne, np. obliczanie pierwiastka kwadratowego.
  • net/http: Pozwala na tworzenie serwerów i klientów HTTP.
  • os: Umożliwia interakcję z systemem operacyjnym, np. odczytywanie zmiennych środowiskowych.
  • strings: Zawiera funkcje do manipulacji łańcuchami znaków.

Aby skorzystać z pakietu, musimy go zaimportować na początku pliku za pomocą słowa kluczowego import. Oto przykład importowania pakietu fmt:

package main

import "fmt"

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

W tym przykładzie importujemy pakiet fmt, a następnie używamy funkcji Println z tego pakietu do wyświetlenia tekstu.

Możemy zaimportować wiele pakietów w jednej deklaracji importu, grupując je w nawiasach:

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println("Pierwiastek z 16 to:", math.Sqrt(16))
}

Importowanie pakietów z zewnątrz

Oprócz pakietów standardowych, możesz korzystać z pakietów dostępnych w Internecie. Najpopularniejszym źródłem jest Go Modules, które pozwalają na zarządzanie zależnościami projektu.

Aby zaimportować pakiet zewnętrzny, musisz znać jego ścieżkę. Na przykład, popularnym pakietem do obsługi JSON jest encoding/json. Importuje się go tak samo jak pakiet standardowy:

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
    data := []byte(`{"name": "Jan", "age": 30}`)
	var person Person

    err := json.Unmarshal(data, &person)
    if err != nil {
        fmt.Println("Błąd podczas dekodowania JSON:", err)
        return
    }
    fmt.Printf("Imię: %s, Wiek: %d\n", person.Name, person.Age)
}

W tym przykładzie importujemy pakiet encoding/json, tworzymy strukturę Person i za pomocą funkcji Unmarshal dekodujemy dane w formacie JSON. Po wpisaniu tego kodu możesz go uruchomić, jeśli masz odpowiednio skonfigurowane środowisko dla modułów. Jeśli nie posiadasz jeszcze modułu, możesz go zainicjalizować poleceniem: go mod init example/my-app, a następnie wpisać ten kod w plik main.go. Uruchomić kod możesz poleceniem go run .

Aby używać pakietów zewnętrznych w swoich projektach, musisz je najpierw zainstalować. Go Modules ułatwiają ten proces. Go samodzielnie będzie śledzić i pobierać potrzebne pakiety.

Widoczność identyfikatorów: Co jest publiczne, a co prywatne?

W Go, widoczność identyfikatorów (np. zmiennych, funkcji, typów) jest kontrolowana przez ich nazwę. Ta zasada jest bardzo prosta:

  • Eksportowane (publiczne) identyfikatory: Zaczynają się z wielkiej litery. Oznacza to, że są dostępne z innych pakietów.
  • Nieeksportowane (prywatne) identyfikatory: Zaczynają się z małej litery. Są dostępne tylko wewnątrz pakietu, w którym zostały zdefiniowane.

To proste podejście jest bardzo skuteczne i promuje pisanie bardziej zorganizowanego i zrozumiałego kodu.

Przykład:

// package mypackage

package mypackage

// Eksportowana funkcja
func Add(a, b int) int {
    return a + b
}

// Nieeksportowana funkcja
func subtract(a, b int) int {
    return a - b
}

// Eksportowana zmienna
var Counter int

// Nieeksportowana zmienna
var internalCounter int

W tym przykładzie, funkcja Add i zmienna Counter są eksportowane i mogą być używane z innych pakietów. Funkcja subtract i zmienna internalCounter są prywatne i mogą być używane tylko w pakiecie mypackage.

Przykład użycia:

package main

import (
    "fmt"
	"example/mypackage"
)

func main() {
    result := mypackage.Add(5, 3)
    fmt.Println("Wynik dodawania:", result) // Wyświetli: Wynik dodawania: 8

    mypackage.Counter = 10
	fmt.Println("Licznik:", mypackage.Counter) // Wyświetli: Licznik: 10

	// Poniższa linijka spowoduje błąd, ponieważ nie możemy się odwołać do nieeksportowanej funkcji
	// mypackage.subtract(10,5)

	// Podobnie nie możemy zmienić wewnętrznej zmiennej pakietu
	// mypackage.internalCounter = 10
}

Tworzenie własnych pakietów

Teraz, gdy wiemy, jak importować pakiety, czas nauczyć się tworzyć własne. To bardzo proste:

  1. Utwórz katalog dla swojego pakietu: Wybierz nazwę dla swojego pakietu i utwórz katalog o tej samej nazwie. Na przykład, utwórz katalog mypackage.
  2. Utwórz plik .go w tym katalogu: Wewnątrz katalogu utwórz plik z rozszerzeniem .go. Na przykład, mypackage.go.
  3. Zadeklaruj pakiet na początku pliku: Na początku pliku użyj słowa kluczowego package, podając nazwę katalogu, który będzie nazwą pakietu. Na przykład: package mypackage.
  4. Dodaj kod: Teraz możesz dodawać zmienne, funkcje, typy i wszystko, czego potrzebujesz. Pamiętaj, aby eksportować elementy, które chcesz udostępnić innym.

Przykład struktury katalogów:

myproject/
  main.go
  mypackage/
    mypackage.go

Zawartość mypackage.go:

package mypackage

// Funkcja do pozdrawiania
func Greet(name string) string {
	return "Witaj, " + name + "!"
}

// Funkcja licząca długość stringa
func Length(text string) int {
    return len(text)
}

// Prywatna zmienna
var secret string = "Shhh!"

// Publiczna zmienna
var Message string = "This is public!"

Zawartość main.go:

package main

import (
    "fmt"
	"example/myproject/mypackage"
)

func main() {
	greeting := mypackage.Greet("Go developer")
	fmt.Println(greeting) // Output: Witaj, Go developer!
	length := mypackage.Length("Hello")
	fmt.Println("Długość stringa:", length) // Output: Długość stringa: 5
	fmt.Println("Publiczny komunikat: ", mypackage.Message) // Output: Publiczny komunikat:  This is public!

	// Poniższa linijka zwróci błąd:
	// fmt.Println(mypackage.secret)
}

Ważne: W tym przykładzie, musisz uruchomić program będąc w katalogu myproject, tak żeby moduły mogły poprawnie zaimportować twój pakiet. Do uruchomienia kodu użyj komendy: go run .

Jasne, oto artykuł na bloga o instalacji pakietów w projekcie Go:

Go Modules

Od wersji Go 1.11, Go używa Go Modules do zarządzania zależnościami projektu. Go Modules to system, który pozwala nam określić, jakie pakiety są potrzebne do naszego projektu i w jakich wersjach. Dzięki temu, możemy łatwo udostępniać nasze projekty i mieć pewność, że inni będą mogli je uruchomić bez problemów.

Inicjalizacja modułu

Aby rozpocząć korzystanie z Go Modules, musimy najpierw zainicjalizować moduł w naszym projekcie. Robimy to za pomocą komendy go mod init. Na przykład, jeśli chcemy utworzyć moduł o nazwie github.com/user/repo, możemy to zrobić tak:

go mod init github.com/user/repo

Ta komenda utworzy plik go.mod w katalogu głównym naszego projektu. Plik ten będzie zawierał informacje o naszym module, takie jak jego nazwa i wersja Go, której używamy.

Dodawanie pakietów

Aby dodać pakiet do naszego projektu, możemy użyć komendy go get. Na przykład, jeśli chcemy dodać pakiet github.com/gorilla/mux, możemy to zrobić tak:

go get github.com/gorilla/mux

Ta komenda pobierze pakiet github.com/gorilla/mux i jego zależności, a następnie doda go do pliku go.mod.

Aktualizacja pakietów

Aby zaktualizować pakiet do najnowszej wersji, możemy użyć komendy go get -u. Na przykład, jeśli chcemy zaktualizować pakiet github.com/gorilla/mux, możemy to zrobić tak:

go get -u github.com/gorilla/mux

Ta komenda pobierze najnowszą wersję pakietu github.com/gorilla/mux i jego zależności, a następnie zaktualizuje plik go.mod.

Usuwanie pakietów

Aby usunąć pakiet z naszego projektu, możemy użyć komendy go mod tidy. Ta komenda usunie z pliku go.mod wszystkie pakiety, które nie są już używane w naszym projekcie.

Przykłady

Oto kilka przykładów użycia pakietów w projekcie Go:

package main

import (
	"fmt"
	"net/http"

	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hello, world!")
	})
	http.ListenAndServe(":8080", r)
}

W tym przykładzie, używamy pakietu github.com/gorilla/mux do utworzenia routera HTTP. Router HTTP to komponent, który pozwala nam mapować adresy URL na funkcje, które będą obsługiwać te adresy.

package main

import (
	"fmt"
	"time"

	"github.com/robfig/cron"
)

func main() {
	c := cron.New()
	c.AddFunc("0 0 * * *", func() {
		fmt.Println("Hello, world!")
	})
	c.Start()
	time.Sleep(time.Hour)
}

W tym przykładzie, używamy pakietu github.com/robfig/cron do utworzenia cron joba. Cron job to zadanie, które jest wykonywane regularnie, zgodnie z harmonogramem. W tym przypadku, cron job będzie wyświetlał komunikat “Hello, world!” co godzinę.

Podsumowanie

Pakiety i importy to podstawowe mechanizmy w Go, które pozwalają na pisanie zorganizowanego i efektywnego kodu. Dzięki nim możemy dzielić kod na logiczne moduły, wykorzystywać bibliotekę standardową oraz korzystać z gotowych rozwiązań udostępnianych przez społeczność.

  • Pakiety: Służą do grupowania kodu. Każdy plik .go musi należeć do pakietu.
  • Importy: Pozwalają na korzystanie z kodu z innych pakietów.
  • Biblioteka standardowa: Zawiera gotowe pakiety do różnych zadań.
  • Widoczność identyfikatorów: Kontrolowana przez wielkość pierwszej litery (eksportowane lub nieeksportowane).
  • Tworzenie własnych pakietów: Prosty proces polegający na utworzeniu katalogu, pliku i zadeklarowaniu pakietu.

Praca Domowa

  1. Utwórz własny pakiet o nazwie mymath, który będzie zawierał dwie funkcje:
    • Add(a, b int) int - zwraca sumę dwóch liczb całkowitych.
    • Multiply(a, b int) int - zwraca iloczyn dwóch liczb całkowitych.
  2. W pliku main.go zaimportuj pakiet mymath i użyj tych funkcji. Wyświetl wyniki.
  3. Utwórz zmienną w pakiecie mymath, która nie będzie eksportowana. Zobacz czy jesteś w stanie się do niej odwołać w pliku main.go.
  4. Poszukaj ciekawego pakietu zewnętrznego i spróbuj go zaimportować i użyć w swoim projekcie.

Zachęcam do eksperymentowania! Im więcej będziesz ćwiczyć, tym szybciej opanujesz te koncepcje. Nie zapomnij także zajrzeć do innych wpisów z serii, aby poznać jeszcze więcej tajników języka Go. Powodzenia!

Polecane artykuły