Menu
CoddyTech

__newindex Metametodu

Coddy'nin Lua Journey'sinin Mantık ve Akış bölümünün bir parçası. Ders 19 / 54.

Bir tabloda bulunmayan bir anahtarı okumaya çalıştığında ne olacağını __index öğesinin nasıl kontrol ettiğini öğrendin. Şimdi onun karşılığını keşfedeceksin: tabloda henüz bulunmayan bir anahtara değer atadığında ne olacağını kontrol eden __newindex.

__newindex meta yöntemi, tabloda şu anda bulunmayan bir anahtara değer atamaya çalıştığında tetiklenir. Bu sayede değişiklikleri gerçekleşmeden önce yakalayıp kontrol edebilirsin.

İşte bir tabloya yeni anahtarların eklenmesini önleyen basit bir örnek:

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

setmetatable(readOnly, meta)

readOnly.name = "Alice"  -- Çıktı: Cannot add key: name
print(readOnly.name)     -- Çıktı: nil

readOnly.name = "Alice" ayarlamaya çalıştığında Lua, tabloda name olmadığını görür. Lua, onu eklemek yerine __newindex işlevini üç bağımsız değişkenle çağırır: tablonun kendisi, ayarlanan anahtar ve atanan değer.

Bu örnekte işlev yalnızca bir mesaj yazdırır ve aslında hiçbir şeyi saklamaz.

Verileri tablonuza eklenmelerine izin vermeden önce doğrulamak için __newindex özelliğini de kullanabilirsiniz:

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"  -- Çıktı: Health must be a number!
player.health = 100     -- İzin verilir, rawset ile saklanır
player.health = "high"  -- Mesaj yok: health artık mevcut

İkinci örnekte rawset() kullanımına dikkat edin. Bu işlev, metatablosunu atlayarak değeri doğrudan tabloya ayarlar.

Bu olmadan, değeri ayarlamak __newindex işlevini yeniden tetikleyerek sonsuz bir döngü oluştururdu.

__newindex yalnızca tabloda bulunmayan anahtarlar için çalıştığından, bu denetim her anahtarın ilk atamasını kontrol eder. rawset, health değerini depoladıktan sonra sonraki atamalar bu değeri doğrudan değiştirir. Her atamayı denetlemek için tablonun kendisini boş tut ve değerleri, tablonun __index aracılığıyla okuduğu ikinci bir tabloda depola:

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"  -- Çıktı: Health must be a number!
print(player.health)    -- Çıktı: 100

player hiçbir zaman kendine ait bir anahtar edinmez; bu nedenle her atama __newindex üzerinden yapılır ve her okuma __index üzerinden data'ya ulaşır.

challenge icon

Görev

Kolay

Yeni anahtarlar için yalnızca dize değerlerini kabul eden ve key ile value alan bir createValidatedTable işlevi yaz.

Boş bir tablo oluştur ve değer türünü doğrulayan __newindex içeren bir metatablo bağla. Birisi dize olmayan bir değer eklemeye çalışırsa, bunun yerine "invalid" dizesini depolamak için rawset() kullan. Dize değerlerini rawset() kullanarak normal şekilde depola.

Mantık:

  • Boş bir tablo oluştur
  • Tabloyu, anahtarı ve değeri alan bir __newindex içeren metatablo oluştur
  • __newindex içinde, type(value) == "string" kullanarak değerin bir dize olup olmadığını kontrol et
  • Değer bir dizeyse, depolamak için rawset(t, key, value) kullan
  • Değer bir dize değilse, bunun yerine "invalid" değerini depolamak için rawset(t, key, "invalid") kullan
  • setmetatable() kullanarak metatabloyu tabloya bağla
  • İlk anahtar-değer çiftini tabloya eklemek için (metatabloyu atlayarak) rawset() kullan
  • Tabloyu döndür

Parametreler:

  • key (dize): Tabloya eklenecek ilk anahtar
  • value (dize): Tabloya eklenecek ilk değer

Döndürdüğü değer: Yalnızca dize değerlerini kabul eden doğrulamaya sahip, ilk anahtar-değer çiftini içeren bir tablo (table)

Kendin dene

function createValidatedTable(key, value)
    -- Kodu buraya yazın
end
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Mantık ve Akış bölümündeki tüm dersler

Kendi başına pratik yap: Online Lua derleyicisi