__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ı: nilreadOnly.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ı: 100player 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.
Görev
KolayYeni 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
__newindexiçeren metatablo oluştur __newindexiç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çinrawset(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 anahtarvalue(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
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
1İleri Düzey Tablo Yineleme
pairs() ile Yinelemeipairs() ile Yinelemepairs() vs. ipairs()Özet - Karakter Sayfası4Metatable'lara Giriş
Metatable Nedir?setmetatable & getmetatable__index Metametodu__newindex Metametodu__tostring MetametoduAritmetik Metametotlar Bölüm 1Aritmetik Metametotlar Bölüm 2Özet - Salt Okunur Tablo2Daha Fazla Tablo Kütüphanesi Fonksiyonu
table.concat()Tablo Oluşturma ve unpack()table.sort()Fonksiyonlar ile Özel SıralamaÖzet - Yüksek Skor TablosuKendi başına pratik yap: Online Lua derleyicisi