Go dla początkujących - Część 3: Funkcje
Mateusz Kędziora

Witaj w kolejnym poście z kursu Go dla początkujących! Dziś zajmiemy się jednym z najważniejszych elementów każdego języka programowania – funkcjami. Funkcje pozwalają nam organizować kod w logiczne bloki, co znacznie ułatwia jego czytanie, pisanie i utrzymanie. W Go funkcje są szczególnie potężne i elastyczne, oferując wiele możliwości, takich jak funkcje anonimowe i closure.
Czym są funkcje?
Funkcja to blok kodu, który wykonuje określone zadanie. Możemy przekazywać do funkcji dane (parametry), a funkcja może zwracać wynik (wartość zwracana). Funkcje pozwalają nam uniknąć powtarzania kodu i zwiększają czytelność programu.
Definiowanie funkcji w Go
Funkcję w Go definiujemy za pomocą słowa kluczowego func
, po którym następuje nazwa funkcji, lista parametrów w nawiasach, typ wartości zwracanej (lub brak wartości, jeśli funkcja nic nie zwraca) oraz ciało funkcji w nawiasach klamrowych.
Oto przykład prostej funkcji, która dodaje dwie liczby całkowite:
func dodaj(a int, b int) int {
return a + b
}
Wywoływanie funkcji
Aby wywołać funkcję, wystarczy podać jej nazwę i wartości argumentów w nawiasach:
wynik := dodaj(5, 3) // wynik będzie równy 8
Parametry funkcji
Funkcje mogą przyjmować dowolną liczbę parametrów różnych typów. Jeśli parametry są tego samego typu, możemy je zadeklarować grupowo:
func dodaj(a, b int) int {
return a + b
}
Wartości zwracane
Funkcja może zwracać jedną lub więcej wartości. Jeśli funkcja zwraca więcej niż jedną wartość, typy tych wartości musimy podać w nawiasach po słowie kluczowym return
:
func podziel(a, b int) (int, int) {
iloraz := a / b
reszta := a % b
return iloraz, reszta
}
Funkcje anonimowe
W Go możemy tworzyć funkcje anonimowe, czyli funkcje bez nazwy. Funkcje anonimowe są często używane jako argumenty innych funkcji lub do tworzenia closure.
Oto przykład funkcji anonimowej, która wyświetla komunikat na ekranie:
func() {
fmt.Println("Witaj, świecie!")
}() // Natychmiastowe wywołanie funkcji
Closure
Closure to funkcja, która “pamięta” wartości zmiennych z jej otoczenia, nawet po tym, jak funkcja zewnętrzna, w której została zdefiniowana, zakończyła swoje działanie. Closure są bardzo przydatne do tworzenia funkcji, które zachowują stan między wywołaniami.
Oto przykład closure, która zlicza, ile razy została wywołana:
licznik := func() int {
i := 0
return func() int {
i++
return i
}
}()
fmt.Println(licznik()) // 1
fmt.Println(licznik()) // 2
fmt.Println(licznik()) // 3
Zastosowanie funkcji w praktyce
Funkcje są nieodzowne w programowaniu w Go. Pozwalają nam dzielić kod na mniejsze, łatwiejsze do zarządzania części. Dzięki funkcjom możemy tworzyć modularny i czytelny kod, który jest łatwiejszy do testowania i debugowania.
1. Funkcje jako argumenty innych funkcji (funkcje wyższego rzędu)
W Go funkcje mogą być przekazywane jako argumenty do innych funkcji. To pozwala na tworzenie bardziej elastycznego i uniwersalnego kodu.
package main
import "fmt"
// Funkcja, która przyjmuje inną funkcję jako argument
func wykonajOperacje(a, b int, operacja func(int, int) int) int {
return operacja(a, b)
}
// Funkcje, które mogą być przekazane jako argument
func dodaj(a, b int) int {
return a + b
}
func odejmij(a, b int) int {
return a - b
}
func main() {
wynikDodawania := wykonajOperacje(5, 3, dodaj) // Przekazujemy funkcję dodaj
fmt.Println("Wynik dodawania:", wynikDodawania) // Wynik dodawania: 8
wynikOdejmowania := wykonajOperacje(5, 3, odejmij) // Przekazujemy funkcję odejmij
fmt.Println("Wynik odejmowania:", wynikOdejmowania) // Wynik odejmowania: 2
}
2. Funkcje zwracające funkcje (domknięcia)
Funkcje w Go mogą również zwracać inne funkcje. To pozwala na tworzenie domknięć (closures), czyli funkcji, które “pamiętają” wartości zmiennych z ich otoczenia, nawet po tym, jak funkcja zewnętrzna, w której zostały zdefiniowane, zakończyła swoje działanie.
package main
import "fmt"
// Funkcja, która zwraca inną funkcję (domknięcie)
func generatorLicznika() func() int {
licznik := 0 // Zmienna lokalna dla funkcji generatorLicznika
return func() int {
licznik++
return licznik
}
}
func main() {
licznik := generatorLicznika() // Przypisujemy domknięcie do zmiennej licznik
fmt.Println(licznik()) // 1
fmt.Println(licznik()) // 2
fmt.Println(licznik()) // 3
}
3. Funkcje w strukturach
Funkcje mogą być również definiowane wewnątrz struktur. Takie funkcje nazywamy metodami. Metody działają na konkretnych instancjach struktur i mają dostęp do ich pól.
package main
import "fmt"
// Definiujemy strukturę Prostokat
type Prostokat struct {
szerokosc float64
wysokosc float64
}
// Metoda, która oblicza pole prostokąta
func (p Prostokat) pole() float64 {
return p.szerokosc * p.wysokosc
}
func main() {
prostokat := Prostokat{szerokosc: 5, wysokosc: 3}
fmt.Println("Pole prostokąta:", prostokat.pole()) // Pole prostokąta: 15
}
4. Funkcje w interfejsach
Interfejsy w Go definiują zbiór metod, które typ musi implementować, aby spełniał dany interfejs. Funkcje są więc nieodłącznie związane z interfejsami.
package main
import "fmt"
// Definiujemy interfejs Figura
type Figura interface {
pole() float64
}
// Struktura Prostokat implementuje interfejs Figura
type Prostokat struct {
szerokosc float64
wysokosc float64
}
func (p Prostokat) pole() float64 {
return p.szerokosc * p.wysokosc
}
// Funkcja, która przyjmuje argument typu Figura
func wyswietlPole(f Figura) {
fmt.Println("Pole figury:", f.pole())
}
func main() {
prostokat := Prostokat{szerokosc: 5, wysokosc: 3}
wyswietlPole(prostokat) // Pole figury: 15
}
5. Funkcje w pakietach
W Go funkcje są podstawowym elementem organizacji kodu w pakiety. Każdy pakiet może zawierać wiele funkcji, które mogą być używane przez inne pakiety.
// Pakiet math
package math
// Funkcja eksportowana (zaczyna się od dużej litery)
func Dodaj(a, b int) int {
return a + b
}
// Funkcja nieeksportowana (zaczyna się od małej litery)
func odejmij(a, b int) int {
return a - b
}
// W innym pakiecie
package main
import (
"fmt"
"mojaaplikacja/math" // Importujemy nasz pakiet math
)
func main() {
wynik := math.Dodaj(5, 3) // Używamy funkcji z pakietu math
fmt.Println("Wynik dodawania:", wynik) // Wynik dodawania: 8
}
Mam nadzieję, że te przykłady pomogą Ci lepiej zrozumieć, jak używać funkcji w języku Go. Zachęcam do eksperymentowania i tworzenia własnych funkcji, aby jeszcze lepiej opanować ten ważny element języka.
Praca domowa
- Napisz funkcję, która oblicza pole prostokąta.
- Napisz funkcję, która sprawdza, czy liczba jest parzysta, czy nieparzysta.
- Napisz funkcję, która zwraca największy element z listy liczb.
- Spróbuj napisać własny przykład użycia closure.
Podsumowanie
Funkcje to kluczowy element języka Go. Dzięki nim możemy pisać modularny, czytelny i łatwy w utrzymaniu kod. Zachęcam do eksperymentowania z funkcjami, pisania własnych przykładów i odkrywania ich możliwości.
Zapraszam do lektury kolejnych postów z kursu Go dla początkujących, w których omówimy kolejne ciekawe tematy.
Polecane artykuły
Docker vs Kubernetes: Który dla Ciebie w 2025?
Docker i Kubernetes objaśnione! Która technologia lepsza dla początkujących w 2025? Porównanie, przykłady i przyszłość.
Mateusz Kędziora
DevOps: Automatyzacja zadań sysadmina dla programistów
Zautomatyzuj pracę sysadmina w środowisku DevOps! Praktyczne przykłady, skrypty, Ansible, Terraform, Prometheus i Grafana.
Mateusz Kędziora
Automatyzacja Linux/macOS z Bash: Praktyczny Przewodnik
Zacznij automatyzować system Linux/macOS z Bash! Dowiedz się, czym jest Bash, jak pisać skrypty i używać podstawowych komend.
Mateusz Kędziora