1 Podstawy funkcji
W programowaniu funkcja to fragment kodu, który wykonuje określone zadanie i może mieć parametry wejściowe oraz wartości zwracane. W języku Go funkcje są szeroko wykorzystywane do organizowania i ponownego wykorzystywania kodu. Skuteczne wykorzystanie funkcji może sprawić, że kod będzie bardziej zwięzły, łatwy do czytania i łatwy w utrzymaniu.
Funkcje stanowią kluczowy element języka Go, a zrozumienie sposobu deklaracji i definiowania funkcji jest kluczowe dla pisania wydajnego i czytelnego kodu.
2 Definiowanie funkcji
2.1 Deklaracja funkcji
W języku Go ogólna postać deklaracji funkcji jest następująca:
func nazwaFunkcji(parametry) typZwracany {
// Ciało funkcji
}
Rozłóżmy te składniki:
- Słowo kluczowe
func
służy do deklaracji funkcji. -
nazwaFunkcji
to nazwa funkcji, zgodna z konwencją nazewnictwa języka Go. Funkcja z wielką literą na początku jest eksportowana, co oznacza, że jest widoczna poza pakietem; funkcja z małą literą na początku nie jest eksportowana i może być używana tylko w tym samym pakiecie. -
parametry
to lista parametrów, które funkcja otrzymuje, oddzielone przecinkami. Należy określić typ każdego parametru, a jeśli wiele parametrów ma ten sam typ, można określić typ tylko raz. -
typZwracany
to typ wartości zwracanej przez funkcję. Jeśli funkcja nie zwraca wartości, ten fragment można pominięć. Jeśli funkcja zwraca wiele wartości, należy je umieścić w nawiasach.
Na przykład możemy zadeklarować prostą funkcję obliczającą sumę dwóch liczb całkowitych:
func Dodaj(a int, b int) int {
return a + b
}
W tym przykładzie nazwa funkcji to Dodaj
, przyjmuje ona dwa parametry typu int
(a i b) i zwraca ich sumę o typie int.
2.2 Lista Parametrów
Lista parametrów określa, jakie parametry przyjmuje funkcja i jaki jest typ każdego parametru. Parametry są specjalnym rodzajem zmiennej używanej do przekazywania danych do funkcji.
func Przywitaj(imie string, wiek int) {
fmt.Printf("Cześć, %s! Masz %d lat.\n", imie, wiek)
}
W funkcji Przywitaj
, imie
i wiek
są parametrami. Typ imie
to string
, a typ wiek
to int
. Podczas wywoływania tej funkcji należy podać rzeczywiste wartości dla tych parametrów.
2.3 Typy Zwracane
Funkcje mogą zwracać obliczone wyniki, a typ zwracany określa typ danych zwracanych przez funkcję. Funkcje mogą nie zwracać wartości lub mogą zwracać jedną lub więcej wartości.
Jeśli funkcja ma wiele wartości zwracanych, ich typy powinny być umieszczone w nawiasach podczas deklaracji:
func Podziel(dzielna, dzielnik float64) (float64, error) {
if dzielnik == 0 {
return 0, errors.New("nie można dzielić przez zero")
}
return dzielna / dzielnik, nil
}
Funkcja Podziel
zwraca tutaj dwie wartości: iloraz oraz komunikat błędu. Jeśli dzielnik wynosi zero, zwracany jest błąd.
2.4 Parametry Zmiennoliczbowe
W języku Go, gdy nie jesteśmy pewni, ile parametrów poda wywołujący przy definiowaniu funkcji, możemy użyć parametrów zmiennoliczbowych. Parametry zmiennoliczbowe oznacza się za pomocą wielokropka ...
, co oznacza, że funkcja może przyjmować dowolną liczbę parametrów. Jest to bardzo przydatne przy pracy z niepewną ilością danych albo implementacji określonych typów funkcji, takich jak formatowanie, podsumowywanie lub iteracyjne funkcje.
Scenariusze zastosowań
Parametry zmiennoliczbowe są powszechnie wykorzystywane w następujących scenariuszach:
-
Łączenie ciągów znaków: np. funkcje
fmt.Sprintf
istrings.Join
. - Przetwarzanie tablicy/slice'a: podczas operowania na tablicach lub slice'ach o zmiennej długości, jak obliczanie sumy lub łączenie wielu slice'ów.
-
Rejestrowanie i obsługa błędów: podczas obsługi wielu błędów lub zapisywania wielu informacji dziennika, np.
log.Printf
lub funkcje podsumowujące błędy niestandardowe. - Funkcje pomocnicze: używane w interfejsach API lub bibliotekach, aby zapewnić użytkownikom bardziej elastyczny sposób wywoływania funkcji.
Korzystanie z parametrów zmiennych
Oto prosty przykład korzystania z parametrów zmiennych:
// Zdefiniuj funkcję, która przyjmuje zmienną liczbę parametrów całkowitych i zwraca ich sumę
func Sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
// Możesz przekazywać dowolną liczbę parametrów
fmt.Println(Sum(1, 2)) // Wynik: 3
fmt.Println(Sum(1, 2, 3, 4)) // Wynik: 10
// Możesz także przekazać slice i użyć wielokropka po slicu
numbers := []int{1, 2, 3, 4, 5}
fmt.Println(Sum(numbers...)) // Wynik: 15
}
W funkcji Sum
, nums
jest slice'em liczb całkowitych zawierającym wszystkie parametry przekazane do funkcji Sum
. Możemy użyć pętli range
do iteracji po tym slicu i obliczenia sumy.
Warto zauważyć, że parametry zmiennych wewnątrz funkcji są w rzeczywistości slicem, dlatego można używać wszystkich operacji związanych ze slicami. Gdy potrzebujesz przekazać slice jako parametr zmienny do funkcji, po prostu dodaj wielokropek ...
po slicu.
Korzystanie z parametrów zmiennych może uczynić wywołania funkcji bardziej elastycznymi i zwięzłymi, ale również wpłynie nieco na wydajność, ponieważ korzystanie z parametrów zmiennych wiąże się z tworzeniem sliców i alokacją pamięci. Dlatego należy ostrożnie postępować, gdy istnieją surowe wymagania wydajnościowe.
Wskazówka: Szczegółowe wyjaśnienie dotyczące sliców zostanie podane w późniejszych rozdziałach. Jeśli masz doświadczenie z innymi językami programowania, możesz tymczasowo myśleć o nich jako tablicach.
3 Wywoływanie funkcji
3.1 Podstawowe wywołania funkcji
Wywołanie funkcji oznacza wykonanie kodu funkcji. W Go wywołanie zdefiniowanej funkcji jest bardzo proste, po prostu użyj nazwy funkcji i przekaż odpowiednie parametry. Na przykład:
result := add(3, 4)
fmt.Println(result) // Wynik: 7
W tym przykładzie funkcja add
jest wywoływana, a następnie przekazywane są jej dwa liczby całkowite, a zwrócony wynik jest przypisywany do zmiennej result
.
3.2 Przekazywanie parametrów
Podczas przekazywania parametrów do funkcji, Go domyślnie używa przekazywania przez wartość, co oznacza przekazanie kopii wartości parametru, a oryginalne dane nie zostaną zmienione. Jednak jeśli chcesz, aby funkcja modyfikowała zmienne zewnętrzne lub z przyczyn wydajnościowych, można użyć przekazywania przez referencję, na przykład za pomocą wskaźników lub przekazywania dużych struktur.
Oto przykłady przekazywania przez wartość i przez referencję:
// Przykład przekazywania przez wartość
func double(val int) {
val *= 2
}
// Przykład przekazywania przez referencję
func doublePtr(val *int) {
*val *= 2
}
func main() {
value := 3
double(value)
fmt.Println(value) // Wynik: 3, wartość pozostaje niezmieniona
doublePtr(&value)
fmt.Println(value) // Wynik: 6, wartość podwojona
}
W powyższym przykładzie funkcja double
próbuje podwoić przekazaną wartość val
, ale podwaja tylko jej kopię, pozostawiając oryginalną zmienną value
niezmienioną. Jednak funkcja doublePtr
zmienia wartość oryginalnej zmiennej, odbierając wskaźnik do zmiennej całkowitoliczbowej jako parametr.