vararg i zasięg zmiennych

Czasem nie wiemy z góry, ile argumentów trafi do funkcji – z pomocą przychodzi vararg. Poznasz też zasięg zmiennych (gdzie zmienna jest widoczna) oraz – krótko – funkcje lokalne, czyli funkcje wewnątrz funkcji.

vararg zasięg zmiennych funkcje lokalne Lekcja 3.4
1

vararg – zmienna liczba argumentów

Słowo vararg przed parametrem pozwala przekazać funkcji dowolnie wiele argumentów tego samego typu – zero, jeden, kilka albo kilkadziesiąt. Wewnątrz funkcji trafiają one do jednej nazwy.

Suma dowolnej liczby liczb
fun suma(vararg liczby: Int): Int {
    var wynik = 0
    for (l in liczby) {
        wynik += l
    }
    return wynik
}

fun main() {
    println(suma(1, 2, 3))     // 6
    println(suma(10, 20))      // 30
    println(suma(5))           // 5
    println(suma())            // 0  (zero argumentów też jest OK)
}
2

vararg to zbiór wartości

Wewnątrz funkcji parametr vararg zachowuje się jak zbiór wartości, po którym można przejść pętlą for. Ma też gotowe właściwości i metody, np. .size (ile elementów) czy .sum().

Statystyki ocen
fun statystyki(vararg oceny: Int) {
    println("Liczba ocen: ${oceny.size}")
    println("Suma:        ${oceny.sum()}")
    println("Najwyższa:   ${oceny.max()}")
}

statystyki(5, 3, 4, 6, 2)
// Liczba ocen: 5
// Suma:        20
// Najwyższa:   6
Gotowe metody na liczbach

Metody .sum(), .max() czy .average() liczą wynik bez ręcznej pętli. Więcej takich „skrótów” na zbiorach poznasz w bloku o kolekcjach – tutaj wykorzystujemy je przy okazji vararg.

3

vararg z innymi parametrami

Funkcja może mieć też zwykłe parametry obok vararg. Aby uniknąć niejasności, vararg umieszczamy zwykle na końcu listy. W jednej funkcji może być tylko jeden parametr vararg.

Tytuł + dowolnie wiele wartości
fun raport(tytul: String, vararg wartosci: Int) {
    println("== $tytul ==")
    for (w in wartosci) {
        println("- $w")
    }
}

raport("Wyniki klasy", 5, 3, 4)
Przekazanie gotowego zbioru

Jeśli masz już wartości zebrane w jednym miejscu (np. w tablicy), możesz je „rozsypać” do vararg operatorem *: suma(*tablica). Tablice i kolekcje poznasz w osobnym bloku – wtedy ten zapis stanie się w pełni jasny.

4

Zasięg zmiennych

Zasięg to obszar kodu, w którym zmienna jest widoczna i można jej używać. Zasada jest prosta: zmienna żyje od miejsca deklaracji do końca bloku { }, w którym powstała.

Zmienna z bloku znika poza nim
fun main() {
    val x = 10            // widoczne w całym main

    if (x > 5) {
        val y = 20        // widoczne TYLKO w tym bloku if
        println(x + y)    // OK – x i y są tu widoczne
    }

    // println(y)        // BŁĄD! y już nie istnieje poza blokiem if
}
Parametry i zmienne pętli też mają zasięg

Parametry funkcji są widoczne tylko w jej wnętrzu, a zmienna pętli (i w for) – tylko w tej pętli. Dzięki temu nazwy się nie „mieszają” między różnymi częściami programu.

5

Funkcje lokalne (krótko)

Funkcję można zdefiniować wewnątrz innej funkcji. Taka funkcja lokalna jest widoczna tylko w funkcji, która ją otacza, i ma dostęp do jej zmiennych. Przydaje się, gdy jakiś fragment logiki powtarza się tylko w jednym miejscu.

Funkcja pomocnicza w środku
fun przywitajWszystkich(vararg imiona: String) {

    fun przywitaj(imie: String) {     // funkcja lokalna
        println("Cześć, $imie!")
    }

    for (imie in imiona) {
        przywitaj(imie)                  // wywołanie funkcji lokalnej
    }
}

przywitajWszystkich("Anna", "Krzysztof", "Ola")
Na razie tylko sygnalizujemy

Funkcja lokalna „widzi” zmienne funkcji, w której się znajduje. To wygodne, ale stosuj ją z umiarem – jeśli fragment logiki przyda się też gdzie indziej, lepiej zrobić z niego zwykłą funkcję na zewnątrz.

6

Częste błędy

❌ Błąd 1: użycie zmiennej poza jej zasięgiem

❌ Zmienna z if użyta na zewnątrz

if (warunek) {
    val wynik = 42
}
println(wynik)
// Błąd! wynik istnieje
// tylko w bloku if

✅ Zadeklaruj w szerszym zasięgu

val wynik = if (warunek) 42 else 0
println(wynik)
// wynik widoczny dalej

❌ Błąd 2: traktowanie vararg jak jednej liczby

❌ Działanie wprost na vararg

fun suma(vararg liczby: Int): Int {
    return liczby + 1
    // Błąd! liczby to zbiór,
    // nie pojedyncza liczba

✅ Przejdź po elementach

fun suma(vararg liczby: Int): Int {
    var w = 0
    for (l in liczby) w += l
    return w
}

❌ Błąd 3: dwa parametry vararg

❌ Więcej niż jeden vararg

fun f(vararg a: Int,
      vararg b: Int) {}
// Błąd! tylko jeden vararg
// na funkcję

✅ Jeden vararg, na końcu

fun f(etykieta: String,
      vararg a: Int) {}

❌ Błąd 4: wywołanie funkcji lokalnej z zewnątrz

❌ Lokalna niewidoczna na zewnątrz

fun zewnetrzna() {
    fun lokalna() { }
}
lokalna()
// Błąd! lokalna istnieje
// tylko w zewnetrzna()

✅ Wyciągnij ją na zewnątrz

fun lokalna() { }
fun zewnetrzna() {
    lokalna()
}
lokalna()
7

Podsumowanie

  • vararg pozwala przekazać dowolnie wiele argumentów tego samego typu (także zero).
  • Wewnątrz funkcji vararg to zbiór wartości – działa z for, ma .size, .sum() itd.
  • vararg umieszczamy zwykle na końcu; może być tylko jeden na funkcję.
  • Zasięg: zmienna żyje od deklaracji do końca bloku { }, w którym powstała.
  • Parametry i zmienne pętli też mają swój zasięg – nie wychodzą poza swoje miejsce.
  • Funkcja lokalna to funkcja wewnątrz funkcji – widoczna tylko w niej i mająca dostęp do jej zmiennych.
8

Zadania do wykonania

Zadania wykonaj w Kotlin Playground (play.kotlinlang.org).

Zadanie 1 łatwe

Napisz funkcję suma(vararg liczby: Int): Int sumującą wszystkie przekazane liczby. Wywołaj ją z dwiema, czterema i zerem argumentów.

Zadanie 2 łatwe

Napisz funkcję statystyki(vararg oceny: Int), która wypisuje liczbę ocen, ich sumę i średnią. Skorzystaj z .size i .sum().

Zadanie 3 łatwe

Napisz fragment kodu, w którym zadeklarujesz zmienną wewnątrz bloku if i spróbujesz użyć jej poniżej. Zaobserwuj błąd, a następnie popraw kod tak, by zmienna była widoczna w potrzebnym miejscu.

Zadanie 4 średnie

Napisz funkcję raportSprzedazy(sprzedawca: String, vararg kwoty: Int), która wypisuje nagłówek z nazwiskiem sprzedawcy, a potem każdą kwotę. Wewnątrz użyj funkcji lokalnej formatującej pojedynczą kwotę (np. dodającej „ zł”). Wywołaj funkcję dla kilku kwot.