Metametodlar

Metamethod Nedir?

Metamethod'lar, Lua tabloları üzerinde gerçekleştirilen belirli işlemleri geçersiz kılmanıza olanak tanıyan özel fonksiyonlardır. Bir metamethod tablosu başka bir tabloya uygulandığında, o tablonun Meta Tablosu olarak bilinir. Doğru kullanıldığında, tabloların başka türlü mümkün olmayan çok benzersiz ve karmaşık şekillerde davranmasını sağlayabilirler. Ayrıca Lua'daki nesne yönelimli programlamanın arkasındaki güç merkezidirler.

Lua'da metatable'lar olmadan da tatmin edici bir hayat sürebilirsiniz, ancak umarız pratik bir örnekle onların ne kadar kullanışlı olduğunu görürsünüz.

Burada bir metatable'ın bazı metamethod'larının nasıl bir araya geldiği gösterilmektedir.

local meta = {} -- Tabloyu bir fonksiyon gibi çağırdığınızda ( something() ), metamethod -- __call çağrılacaktır (adı da buradan gelir) ve ilk argüman olarak -- tablo ("self" ile gösterilir) ve geçirilen argümanlar kullanılır. function meta.__call( self, var ) self.myvar = var return var + self:Cheese() end local metaIndex = {} -- __index bir tablo veya bir fonksiyon olabilir, bu örnekte bir fonksiyondur. -- __index, normal tabloda görünmeyen fonksiyonları çağırmanıza olanak tanır. -- "Cheese" metamethod'u, asıl tabloda var olan "myvar" değişkenini döndüren basit bir metamethod'dur. -- Unutmayın, __index içinde bir method çağırıyorsanız, tabloyu ilk argüman olarak geçirmeniz veya -- fonksiyonu çağırırken iki nokta üst üste (:) kullanmanız gerekir. function metaIndex.Cheese( self ) return self.myvar end meta.__index = metaIndex local myObject = {} setmetatable( myObject, meta ) -- Metatable'ı kuruyoruz. print( myObject( 5 ) ) -- 10 print( myObject.myvar ) -- 5 -- Değişkeni manuel olarak ayarlasanız bile, Cheese metamethod'u yine de değişkenin değerini çıktı olarak verecektir. myObject.myvar = 3 print( myObject:Cheese() ) -- 3

Dikkate Değer Kullanımlar

Metamethod'ların belki de en kullanışlı olanları __call ve __index girişleridir.

__call

__call, bir metatable'a sahip tabloların bir fonksiyon gibi çağrılmasına olanak tanır ve bu çağrıda tablo ilk argüman olarak geçirilir.

local meta = {} -- Bu, function meta:__call( key ) ile aynıdır function meta.__call( self ) self.x = ( self.x or 0 ) + 1 return self.x end local tbl = setmetatable( { x = 5 }, meta ) print( tbl.x ) -- 5 print( tbl() ) -- 6 print( tbl.__call ) -- nil

__index

__index çok daha ilginçtir ve metamethod'lara güçlerinin çoğunu veren şeydir. Bir tablo veya bir fonksiyon olabilir.

Eğer bir tabloysa, nesne belirtilen anahtar için içindeki girişlere bakacaktır. Bu, meta.__index tablosunda tanımlanan fonksiyonların nesne tablosu üzerinde çağrılmasına olanak tanıyan şeydir. İlk örnekte yazılan "metaIndex" değişkenine bakın.

Eğer bu index tablosunun da kendi metatable'ı varsa ve anahtarı bulamazsa, bu yeni metatable kullanılacak ve bir dönüş değerine veya index zincirinin sonuna ulaşana kadar (hangisi önce gelirse) zinciri takip edecektir. İşte bunun neye benzediğine dair bir örnek.

local metaApple = { apple = "apples" } local metaPear = { pear = "pears" } local metaOrange = { orange = "oranges" } setmetatable( metaApple, { __index = metaPear } ) setmetatable( metaPear, { __index = metaOrange } ) local mytbl = {} setmetatable( mytbl, { __index = metaApple } ) print( mytbl.orange ) -- "oranges"

Doğru kullanıldığında, bu, entity .Base kalıtımının çalışma şekline çok benzer sonuçlar elde etmenizi sağlar.

Ve eğer bir fonksiyonsa, fonksiyonu çağıracak ve döndürülen değeri sağlayacaktır. Bu örnek, bir tabloya "varsayılan bir değer" vermenin en basit yoludur.

local meta = {} -- Bu, function meta:__index( key ) ile aynıdır function meta.__index( self, key ) return "cheese" end local tbl = setmetatable( { apple = "Apples" }, meta ) print( tbl.apple ) -- "Apples" print( tbl.orange ) -- "cheese"
Bir tabloyu kendi index fonksiyonu içinden indexlemeye çalışmak, doğru yazılmazsa sonsuz döngüye neden olabilir. Ayrıca, metatable'larındaki __index ve __newindex gibi metamethod'ları çağırmadan tablolar üzerinde işlem yapacak olan ve sonsuz döngüyü önlemek için kullanılabilecek rawget ve rawset'e de bakın.

Metatable'ın __index girişini metatable'a referans verecek şekilde ayarlayarak, burada gösterilenden çok daha küçük ve daha az karmaşık metatable'lar yazmak mümkündür. Örnek:

local meta = {} meta.__index = meta -- Bu, function meta.Cheese( self ) ile aynıdır function meta:Cheese() print(self.myvar) end local mytbl = {} setmetatable( mytbl, meta ) mytbl.myvar = "Kittens" mytbl:Cheese() -- "Kittens"

Metatable'ları yazmanın birçok farklı yolu vardır ve hepsi onu ne için kullanacağınıza ve Lua nesnelerinin ne yapmasına ihtiyacınız olduğuna bağlıdır.

Tüm Metamethod'ların Listesi

Tüm metamethod adları __ ile başlar ve mantıksal olarak adlandırılır (ör. __add, + operatörüne karşılık gelir).
Her bir metamethod'un daha ayrıntılı açıklamaları için bu sayfaya bakın.

Örnekle Öğrenin

Yaygın bir programlama görevi, bir öğeyi birçok öğeyle karşılaştırmaktır. Örneğin, bir oyuncunun bir anahtar kelime söyleyip söylemediğini kontrol etmek istediğimizde, table.HasValue kullanabilirsiniz

local fruits = { "banana", "apple", "strawberry", "orange" } -- Sadece bu öğelerle sınırlı değildir. local word = "orange" if table.HasValue( fruits, word ) then print( "The word is a fruit!" ) end

Bu yaklaşımla ilgili sorun, HasValue'nin esasen meyve değişkeninin kelime değişkenine eşit olup olmadığını kontrol eden bir for döngüsü olmasıdır. Büyük tablolarla, HasValue'yi yeterince sık kontrol ederseniz, programınızı gerçekten yavaşlatacaktır! Bunun yerine, aşağıdakileri yaparak bunu daha verimli hale getirebiliriz.

local hasFruit = { banana = true, apple = true, orange = true } -- artı 2000 diğer meyve local word = "orange" if hasFruit[ word ] then print( "The word is a fruit!" ) end

Bu çözüm oldukça şıktır. hasFruit[...] kelime tablomuzdaysa true, değilse nil döndürür.

Metatable Örneği

Birden fazla metamethod'u kullanıma sokan bir örnek, metamethod'larla neler yapabileceğinizin olanaklarını gösteren bu Set betiğidir. Aşağıdaki kodu lua/autorun klasöründe özel bir .lua betiği oluşturarak kolayca çalıştırabilirsiniz. İyi öğrenmeler!

Set = {} -- Bu metatable hem metamethod'ları hem de normal method'ları tutacaktır -- Set.new, sadece 'Set' tablosundaki 'new' fonksiyonudur, sihirli bir şey değil. -- Bu method, tabloyu bizim için oluşturarak hayatımızı kolaylaştırır. function Set:new(items) local set = {} -- daha önceki gibi verimli bir arama tablosu oluştur for key, item in pairs(items) do set[item] = true end -- yeni arama tablomuzu Set metatable'ındaki metamethod'ları kullanacak şekilde ata. setmetatable(set, Set) return set end -- Kümemiz belirtilen öğeyi içeriyorsa true, aksi takdirde false döndürür. -- İki nokta üst üste (:) methodu, Set.contain(self, item) ile aynıdır. Yani, -- 'self' bizim değerler tablomuzdur. function Set:contain(item) return self[item] == true end -- tostring'i aşırı yüklemezsek, nesnenin türünü ve bellekteki yerini yazdıracaktır. (ör: "table: 0x125"). function Set:__tostring() return "{" .. table.concat(table.GetKeys(self), ", ") .. "}" end -- '+' operatörünü geçersiz kılma. -- Mevcut bir kümeye ekleme 'set = set + 1' gibi bir şeye benzeyecektir. -- Eğer 'set:Add(1)' tercih ediyorsanız, contains methodunu şablon olarak kullanın. function Set:__add(other) if type(other) == "table" then -- kümeler birleştirilir if getmetatable(other) == nil then -- 'other' ham bir tablodur for key, item in pairs(other) do self[item] = true end else -- 'other' zaten bir Set'tir (değerleri true olarak ayarlanmıştır) for key, item in pairs(other) do self[key] = true end end else -- tek değerler sona eklenir self[other] = true end return self end -- Son bir parça kullanışlı metamagic setmetatable(Set, { __call = Set.new }) -- Set.new() veya Set()'e izin ver Set.__index = Set -- Set örnek method'larını kullanmamıza izin ver

Basit Bir Test

local fruits = Set( { "banana", "apple", "strawberry", "orange" } ) + "grape" local word = "grape" if fruits:contain( word ) then -- fruits[word] de çalışır print( fruits ) end

Tüm meyveler beklendiği gibi yazdırılır, ancak bunun sırasız bir öğe kümesi olduğunu unutmayın. Onları belirli bir sırada istiyorsanız, sıralamanız gerekecektir.

Ayrıca Bakınız

Metatables and Metamethods (Lua'da Programlama)

Tüm sunucular · GmodTR Launcher · Rehber · GMod Wiki · GmodTR nedir? · Sunucu ekle · Discord