0Pricing
Lua Academy · Pelajaran

__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)  -- 20

Tabel 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 table

Melacak 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)
end

Objek 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) -- 20

Rantai __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 -> 100

Pemeriksaan 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/rawset di 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

  1. Pengantar Metatabel
  2. __index dan __newindex
  3. Metamethod Aritmetika
  4. __tostring dan __len
← Kembali ke Lua Academy