Menu
CoddyTech

Metametoda __newindex

Część sekcji Logika i przepływ programu ścieżki Lua w Coddy. Lekcja 19 z 54.

Dowiedziałeś się, jak __index kontroluje to, co się dzieje, gdy próbujesz odczytać klucz, który nie istnieje w tablicy. Teraz poznasz jego odpowiednik: __newindex, który kontroluje to, co się dzieje, gdy przypisujesz wartość do klucza, którego tablica jeszcze nie zawiera.

Metametoda __newindex jest wywoływana za każdym razem, gdy próbujesz przypisać wartość do klucza, który obecnie nie istnieje w tabeli. Dzięki temu możesz przechwytywać i kontrolować modyfikacje, zanim do nich dojdzie.

Oto prosty przykład, który uniemożliwia dodawanie nowych kluczy do tabeli:

local readOnly = {}
local meta = {
    __newindex = function(table, key, value)
        print("Cannot add key: " .. key)
    end
}

setmetatable(readOnly, meta)

readOnly.name = "Alice"  -- Wynik: Cannot add key: name
print(readOnly.name)     -- Wynik: nil

Gdy próbujesz ustawić readOnly.name = "Alice", Lua widzi, że klucz name nie istnieje w tabeli. Zamiast go dodać, Lua wywołuje funkcję __newindex z trzema argumentami: samą tabelą, ustawianym kluczem i przypisywaną wartością.

W tym przykładzie funkcja po prostu wyświetla komunikat i tak naprawdę niczego nie przechowuje.

Możesz też użyć __newindex, aby zweryfikować dane przed dodaniem ich do swojej tablicy:

local player = {}
local meta = {
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            rawset(t, key, value)
        end
    end
}

setmetatable(player, meta)

player.health = "high"  -- Wynik: Health must be a number!
player.health = 100     -- Dozwolone, zapisane za pomocą rawset
player.health = "high"  -- Brak komunikatu: health już istnieje

Zwróć uwagę na użycie rawset() w drugim przykładzie. Ta funkcja omija metatabelę i bezpośrednio ustawia wartość w tabeli.

Bez tego ustawienie wartości ponownie wywołałoby __newindex, tworząc nieskończoną pętlę.

Ponieważ __newindex uruchamia się tylko dla kluczy, których tabela nie zawiera, to sprawdzenie zabezpiecza pierwsze przypisanie każdego klucza. Gdy rawset zapisze już health, kolejne przypisania zmieniają tę wartość bezpośrednio. Aby sprawdzać każde przypisanie, pozostaw samą tabelę pustą i przechowuj wartości w drugiej tabeli, do której odwołuje się ona przez __index:

local data = {}
local player = setmetatable({}, {
    __index = data,
    __newindex = function(t, key, value)
        if key == "health" and type(value) ~= "number" then
            print("Health must be a number!")
        else
            data[key] = value
        end
    end
})

player.health = 100
player.health = "high"  -- Wynik: Health must be a number!
print(player.health)    -- Wynik: 100

player nigdy nie otrzymuje własnego klucza, więc każde przypisanie przechodzi przez __newindex, a każdy odczyt przechodzi przez __index do data.

challenge icon

Wyzwanie

Łatwy

Napisz funkcję createValidatedTable, która przyjmuje key i value oraz zwraca tabelę akceptującą wyłącznie wartości typu string dla nowych kluczy.

Utwórz pustą tabelę i dołącz do niej metatabelę z polem __newindex, które sprawdza typ wartości. Jeśli ktoś spróbuje dodać wartość inną niż string, użyj rawset(), aby zamiast niej zapisać string "invalid". Wartości typu string zapisuj normalnie za pomocą rawset().

Logika:

  • Utwórz pustą tabelę
  • Utwórz metatabelę z polem __newindex, które otrzymuje tabelę, klucz i wartość
  • Wewnątrz __newindex sprawdź, czy wartość jest typu string, używając type(value) == "string"
  • Jeśli jest typu string, użyj rawset(t, key, value), aby ją zapisać
  • Jeśli nie jest typu string, użyj rawset(t, key, "invalid"), aby zamiast niej zapisać "invalid"
  • Dołącz metatabelę do tabeli za pomocą setmetatable()
  • Użyj rawset(), aby dodać początkową parę klucz-wartość do tabeli (z pominięciem metatabeli)
  • Zwróć tabelę

Parametry:

  • key (string): Początkowy klucz, który należy dodać do tabeli
  • value (string): Początkowa wartość, którą należy dodać do tabeli

Zwraca: Tabelę z walidacją, która akceptuje wyłącznie wartości typu string i zawiera początkową parę klucz-wartość (table)

Spróbuj swoich sił

function createValidatedTable(key, value)
    -- Napisz kod tutaj
end
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Logika i przepływ programu

Poćwicz samodzielnie: Kompilator Lua online