W języku Go organizacja kodu przez pakiety (packages) i system widoczności odgrywa kluczową rolę w modularności, ponownym użyciu i enkapsulacji logiki.
W przeciwieństwie do wielu klasycznych języków z dziedziczeniem obiektowym, Go od podstaw został zaprojektowany wokół prostych modułów — pakietów z wyraźnymi zasadami eksportu i importów. To dziedzictwo filozofii minimalizmu, prostoty i ścisłej kontroli zależności.
Jeśli komponenty nie mają wyraźnej widoczności, rodzi się chaos w nazwach, trudno śledzić zależności między plikami, rośnie ryzyko przypadkowego użycia prywatnych szczegółów implementacji. Błędy w organizacji eksportu mogą prowadzić do trudnych do debugowania błędów i naruszenia enkapsulacji.
W Go każdy plik musi należeć do jakiegoś pakietu (package nazwa). Cała widoczność w Go jest określana przez:
Wszystkie funkcje, typy, zmienne, stałe, metody, których nazwa zaczyna się od wielkiej litery, są eksportowane z pakietu i dostępne dla innych pakietów po imporcie. Pozostałe są dostępne tylko wewnątrz pakietu.
Przykład struktury:
project/
│
├── main.go // package main
└── mathutil/
└── mathutil.go // package mathutil
Przykład kodu:
// mathutil/mathutil.go package mathutil // Public - eksportowana funkcja func Sum(a, b int) int { return a + b } // private - nieeksportowana funkcja func subtract(a, b int) int { return a - b }
// main.go package main import ( "fmt" "project/mathutil" ) func main() { fmt.Println(mathutil.Sum(2, 3)) // 5 // fmt.Println(mathutil.subtract(3,2)) // Błąd kompilacji! subtract nie jest eksportowane }
Kluczowe cechy:
Czy można eksportować zmienną lub funkcję, zadeklarowaną małą literą, innymi mechanizmami?
Nie. W Go nie ma słów kluczowych takich jak public, private, wszystko określa tylko pierwsza litera nazwy (kategoria unicode — wielka litera).
Czy funkcje z jednego pliku pakietu mogą używać prywatnych funkcji z innego pliku tego samego pakietu?
Tak, widoczność ogranicza się na poziomie pakietu, a nie pliku. Wszystkie prywatne elementy są dostępne w wszystkich plikach jednego pakietu.
Przykład kodu:
// mathutil/helpers.go package mathutil func hiddenHelper() int { return 42 } // mathutil/mathutil.go package mathutil func UseHelper() int { return hiddenHelper() // dostępne! }
Czy można stworzyć tę samą funkcję lub typ o tej samej nazwie w obrębie jednej paczki w różnych plikach?
Nie, wystąpi błąd kompilacji — w obrębie pakietu nazwy muszą być unikalne, nawet jeśli zostały zadeklarowane w różnych plikach.
xxx_test.go w tym samym pakiecie)Duży zespół wrzuca wszystkie pomocnicze funkcje i typy do pakietu util z eksportem wszystkiego:
Zalety:
Wady:
Zespół starannie dzieli kod według modułów w obszarach biznesowych, eksportując tylko API:
Zalety:
Wady: