__index dan __newindex
Intersepsi pembacaan dan penulisan bidang dengan metamethod __index dan __newindex.
__index dan __newindex adalah pelajaran Lua Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Lua Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Lua Academy mencakup 4 pelajaran total.
Rangkuman __index
__index dipicu saat Lua mencoba membaca kunci yang tidak ada dalam tabel. Nilainya dapat berupa tabel (pencarian prototipe) atau fungsi (perhitungan dinamis). Ini adalah metametode yang paling sering digunakan dalam Lua—mendukung pewarisan, nilai bawaan, dan inisialisasi malas.
local defaults = {timeout=30, retries=3}
local config = setmetatable({timeout=60}, {__index=defaults})
print(config.timeout) -- 60 (own value)
print(config.retries) -- 3 (from defaults)
print(config.missing) -- nil (not in either)__newindex Dipicu
__newindex dipicu saat Lua mencoba menulis kunci yang belum ada dalam tabel. Jika kunci tersebut sudah ada, penugasan dilakukan secara langsung tanpa memicu __newindex.
local proxy = setmetatable({}, {
__newindex = function(t, k, v)
print("New key:", k, "=", v)
rawset(t, k, v) -- actually store it
end
})
proxy.x = 10 -- New key: x = 10
proxy.x = 20 -- no trigger! x already exists
print(proxy.x) -- 20Tabel Hanya-Baca
Gunakan __newindex untuk membuat tabel hanya-baca. Cegat semua operasi penulisan dan hasilkan error. Gabungkan dengan __index untuk menyediakan nilai tanpa menyimpannya di dalam tabel itu sendiri.
local function readOnly(t)
return setmetatable({}, {
__index = t,
__newindex = function(_, k, _)
error("attempt to write to read-only table key: " .. tostring(k), 2)
end
})
end
local cfg = readOnly({host="localhost", port=8080})
print(cfg.host) -- localhost
-- cfg.host = "x" -- ERROR: attempt to write to read-only tableMelacak Perubahan
Gunakan __newindex untuk melacak semua perubahan pada tabel—berguna untuk debugging, pencatatan perubahan, atau pengikatan data reaktif. Simpan data dalam tabel "pendukung" yang tersembunyi dan catat perubahan dalam log.
local log = {}
local data = {}
local tracked = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
log[#log+1] = {key=k, old=data[k], new=v}
data[k] = v
end
})
tracked.name = "Alice"
tracked.age = 30
tracked.name = "Bob"
for _, entry in ipairs(log) do
print(entry.key, entry.old, "->", entry.new)
endObjek Proksi
Proksi membungkus objek lain untuk mencegat semua operasi baca dan tulis. Gunakan tabel kosong sebagai proksi dengan __index dan __newindex yang sama-sama menunjuk ke fungsi. Data sebenarnya berada di tabel terpisah.
local function makeProxy(target)
return setmetatable({}, {
__index = function(_, k) return target[k] end,
__newindex = function(_, k, v)
print("Setting", k, "on target")
target[k] = v
end,
})
end
local real = {x=10}
local p = makeProxy(real)
print(p.x) -- 10 (reads from real)
p.y = 20 -- Setting y on target
print(real.y) -- 20Rantai __index (Pewarisan)
Merangkai metatabel __index akan membuat pewarisan berbasis prototipe. Saat kunci tidak ditemukan dalam objek, Lua memeriksa kelas, lalu kelas induk, dan seterusnya. Setiap tingkat memerlukan metatabelnya sendiri dengan __index yang menunjuk ke tingkat berikutnya.
local Base = {type = "base", version = 1}
local Child = setmetatable({type = "child"}, {__index = Base})
local Obj = setmetatable({}, {__index = Child})
print(Obj.type) -- base? No: child (Child has it)
print(Obj.version) -- 1 (from Base)
print(Obj.type) -- child (Child overrides Base.type)Inisialisasi Malas dengan __index
Gunakan __index berbentuk fungsi untuk menghitung dan menyimpan nilai mahal saat pertama kali diakses. Pada pembacaan pertama, hitung nilainya dan simpan langsung di dalam tabel (sehingga pemanggilan __index berikutnya dapat dilewati).
local lazy = setmetatable({}, {
__index = function(t, k)
if k == "expensiveData" then
print("Computing...")
local result = {1,2,3,4,5} -- simulate work
rawset(t, k, result)
return result
end
end
})
print(lazy.expensiveData) -- Computing... then table
print(lazy.expensiveData) -- (no "Computing" this time)__newindex untuk Validasi Skema
Gunakan __newindex untuk menerapkan skema: hanya izinkan pengaturan kunci yang telah ditentukan atau nilai dengan tipe yang benar. Ini menambahkan keamanan tipe ringan pada tabel Lua.
local schema = {name="string", age="number", active="boolean"}
local function schemaTable()
local store = {}
return setmetatable({}, {
__index = store,
__newindex = function(_, k, v)
local expected = schema[k]
if not expected then error("unknown key: "..k,2) end
if type(v) ~= expected then
error(k.." must be "..expected..", got "..type(v),2)
end
store[k] = v
end
})
end
local user = schemaTable()
user.name = "Alice"
user.age = 30
-- user.age = "thirty" -- ERROR__index vs rawget
Di dalam fungsi __index, gunakan rawget untuk membaca dari tabel tanpa memicu __index lagi (yang akan menyebabkan rekursi tak terbatas). Selalu gunakan rawget/rawset di dalam metametode untuk memanipulasi penyimpanan tabel yang sebenarnya.
local counter = setmetatable({count=0}, {
__index = function(t, k)
-- Use rawget to avoid recursion
local c = rawget(t, "count")
rawset(t, "count", c + 1)
return rawget(t, k)
end
})
print(counter.count) -- 0 (direct, no __index)
print(counter.missing) -- nil
print(counter.count) -- 1 (incremented)Menggabungkan __index dan __newindex
Pola yang paling kuat: gunakan tabel proksi kosong dengan __index dan __newindex, yang didukung oleh tabel data tersembunyi. Ini memberi Anda kendali penuh atas pembacaan dan penulisan, sehingga memungkinkan fitur seperti pendeteksian perubahan, pemuatan malas, dan pengendalian akses.
local function observable(init)
local data = init or {}
local listeners = {}
local obj = setmetatable({}, {
__index = data,
__newindex = function(_, k, v)
local old = data[k]
data[k] = v
for _, cb in ipairs(listeners) do cb(k,old,v) end
end
})
obj._onchange = function(_, cb) listeners[#listeners+1]=cb end
return obj
end
local obs = observable({score=0})
obs:_onchange(function(k,o,n) print(k,o,"->",n) end)
obs.score = 100 -- score 0 -> 100Pemeriksaan Singkat
Kapan __newindex TIDAK dipicu?
Rangkuman: __index dan __newindex
Poin penting:
__index: dipicu saat membaca kunci yang tidak ada; berupa tabel atau fungsi__newindex: hanya dipicu saat menulis kunci baru- Gunakan
rawget/rawsetdi dalam metametode untuk menghindari rekursi - Pola: tabel hanya-baca, pelacakan perubahan, inisialisasi malas, validasi skema
- Proksi kosong + tabel pendukung = pencegatan penuh terhadap pembacaan/penulisan
Pertanyaan yang Sering Diajukan
Apakah pelajaran “__index dan __newindex” gratis?
Ya — teks lengkap “__index dan __newindex” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Lua Academy, upgrade ke CoddyKit PRO. Kursus Lua Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “__index dan __newindex”?
Intersepsi pembacaan dan penulisan bidang dengan metamethod __index dan __newindex. Kamu berlatih Lua Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Lua Academy?
Tidak diperlukan pengalaman sebelumnya. Lua Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “__index dan __newindex” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Lua Academy ini?
Ya. Setiap pelajaran Lua Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Pengantar Metatabel
- __index dan __newindex
- Metamethod Aritmetika
- __tostring dan __len