Lua deyimler için hemen hemen C ve Pascal 'dakine benzer geleneksel seti destekler. Geleneksel deyimler atama, kontrol yapıları ve prosedür çağrılarını kapsar. Lua aynı zamanda bir kaç tane çok da geleneksel deyimlerden olmayan çoklu atama ve yerel değişken deklarasyonunu da destekler.
4.1 Atama
Atama en basit anlatımla bir tablo alanı veya değişkenin değerini değiştirmektir:
a = "merhaba" .. "dunya" t.n = t.n + 1
Lua bir adımda değişkenler listesine değerler listesinin atandığı çoklu atamaya imkan verir. Her iki liste virgüllerle ayrılmış elemanlara sahiptir. Örneğin şu atamada
a, b = 10, 2*x
a değişkeni 10 değerini alır ve b değişkeni 2*x değerini alır.
Çoklu atamada Lua önce tüm değerleri değerlendirip akabinde atamaları yürütür. Dolayısıyla devamdaki şekilde iki değeri birbiri ile değiştirmek için çoklu atamayı kullanabiliriz
x, y = y, x -- ’x’ ile ’y’ birbiriyle değiştir a[i], a[j] = a[j], a[i] -- ’a[i]’ ile ’a[j]’ birbiriyle değiştir
Lua daima değerler sayısını değişken sayısına ayarlar: değerlerin listesi değişkenlerin listesinden daha kısa olduğunda fazlalık değişkenler nil değeri alır; değerlerin listesi daha uzun olduğunda fazlalık değerler es geçilir:
a, b, c = 0, 1 print(a, b, c) --> 0 1 nil a, b = a+1, b+1, b+2 -- b+2 değeri es geçilir print(a, b) --> 1 2 a, b, c = 0 print(a, b, c) --> 0 nil nil
Yukarıdaki örnekteki son atama yaygın bir hatayı göstermekte. Bir değişkenler setini ilklemek için her biri için bir değer sağlamanız gerekir:
a, b, c = 0, 0, 0
print(a, b, c) --> 0 0 0
Aslında önceki örneklerin çoğu biraz yapay. Tek bir satırda birkaç ilgisiz atama yapmak için nadiren çoklu atama kullanıyorum. Çoklu atama teklisinden daha hızlı değil. Ama çoğu zaman gerçekten çoklu atamaya ihtiyacımız var. Hali hazırda iki değeri birbiri ile değiştirme örneğini gördük. Daha sık kullanımı, fonksiyon çağrılarından birden fazla dönüşü toplamak içindir. Bölüm 5.1'de ayrıntılı olarak ele alacağımız üzere bir fonksiyon çağrısı birden fazla değer döndürebilir.Bu gibi durumlarda tek bir ifade de birkaç değişken için değerler sağlanabilir. Örneğin şu atamada "a,b = f()" , f fonksiyonu iki sonuç döndürür: a ilkini alır ve b ikincisini alır.
4.2 Yerel Değişkenler ve Bloklar
Global değişkenlerin yanı sıra Lua yerel değişkenleri de destekler. local anahtar kelimesiyle ile yerel değişkenleri bildiririz:
j = 10 -- global değişken local i = 1 -- yerel değişken
global değişkenlerden farklı olarak yerel değişkenlerin kapsamları bildirildiği blokla sınırlıdır. Bir blok, bir kontrol yapısının gövdesi, bir fonksiyon gövdesi veya bir öbektir (değişkenin bildirildiği dosya veya string):
x = 10 local i = 1 -- öbeğe yerel while i <= x do local x = i*2 -- while gövdesine yerel print(x) --> 2, 4, 6, 8, ... i = i + 1 end
if i > 20 then local x -- "then" gövdesine yerel x = 20 print(x + 2) -- (test başarılı olursa 22 yazılacak) else print(x) --> 10 (global olan) end print(x) --> 10 (global olan)
Bu örneği etkileşimli modda girerseniz beklendiği gibi çalışmayacağına dikkat. Etkileşimli modda her satır kendi başına bir öbektir(tamamlanmış bir komut olduğu sürece) . Örneğin ikinci satırını (local i=1) girdiğinizde Lua hemen onu çalıştırır ve bir sonraki satırda yeni bir öbek başlatır. O zamanda yerel beyan edilen kapsam dışına çıkar. Bu sorunu çözmek için do–end anahtar kelimeleriyle kapsamlama yaparak tüm bloğu açıkça sınırlayabiliriz. do'ya girildikten sonra komut yalnızca karşılık gelen end de tamamlanır böylece Lua her satırı tek başına yürütmez.
Bazı yerel değişkenlerin kapsamı üzerinde daha ince kontrole ihtiyacınız olduğunda da bu do blokları yararlıdır:
do local a2 = 2*a local d = (b^2 - 4*a*c)^(1/2) x1 = (-b + d)/a2 x2 = (-b - d)/a2 end -- ’a2’ ve ’d’ 'nin kapsamı burada bitiyor print(x1, x2)
Mümkün olduğunca çok yerel değişkenleri kullanmak iyi bir programlama stilidir. Yerel değişkenler genel ortamı gereksiz adlarla kirletmekten kaçınmanıza yardımcı olur. Ayrıca yerel değişkenlere erişim global olanlardan daha hızlıdır. Son olarak, bir yerel değişken normal olarak kapsam biter bitmez işi biter ve değerinin çöp toplayıcı tarafından serbest bırakılmasına imkan verir.
Lua yerel değişken bildirimlerini deyim olarak işler. Bu nedenle bir deyim yazabileceğiniz her yerde yerel bildirimler yazabilirsiniz. Bildirilen değişkenlerin kapsamı bildirimden sonra başlar ve bloğun sonuna kadar gider. Her bildirim geleneksel bir atama ile aynı şekilde çalışan bir ilk atama içerebilir: fazlalık değerler atılır; fazlalık değişkenler nil alır. Bir bildirimin ilk ataması yoksa tüm değişkenleri nil ile ilklenir:
local a, b = 1, 10 if a < b then print(a) --> 1 local a -- tartışmasız ’= nil’ print(a) --> nil end -- ’then’ 'de başlayan bloğun sonu print(a, b) --> 1 10
Lua da yaygın bir deyim,
local foo = foo
Bu kod yerel değişken foo 'u oluşturur ve global değişken foo 'nun değeri ile onu ilkler. (Yerel foo sadece deklarasyonundan sonra görünür hale gelir.) Bu deyim daha sonra başka bir fonksiyon global foo'nun değerini değiştirse bile öbeğin foo'sunun orijinal değerini koruması gerektiğinde yararlıdır; aynı zamanda foo'a erişimi hızlandırır.
Birçok dil bloğun (veya prosedürün) başında tüm yerel değişkenleri bildirmeye zorladığından bazı insanlar bir bloğun ortasında bildirimleri kullanmanın kötü bir uygulama olduğunu düşünür. Tam tersine: bir değişkeni yalnızca ihtiyacınız olduğunda deklare etmeye, nadiren bir başlangıç değeri olmadan bildirmeye ihtiyaç duyarsanız (ve ilklemeyi unutursunuz da). Ayrıca okunabilirliği artıracak olan değişken kapsamını daraltırsınız.
4.3 Kontrol Yapıları
Lua, kontrol yapılarının küçük geleneksel bir setini sağlar, koşullu yürütme için if, yineleme için while, repeat, ve for. Tüm kontrol yapılarının kapsam sonlandırıcısı vardır. if, for ve while yapısı için end. repeat yapısı için until.
Bir kontrol yapısının koşul ifadesi herhangi bir değerde nihayetlenebilir. Lua, false ve nil 'den farklı tüm değerlere true olarak değerlendirir. (Özellikle belirtelim, Lua, 0 ve boş string ikilisini true olarak değerlendirir.)
if then else
Bir if deyimi koşulu test eder ve daha sonra then-bölümünü veya else-bölümünü bu test sonucuna göre yürütür. else kısmı isteğe bağlıdır.
if a < 0 then a = 0 end if a < b then return a else return b end if line > MAXLINES then showpage() line = 0 end
istif şeklinde if'ler yazmak yerine elseif 'i kullanabilirsiniz. elseif, if devamındaki else gibidir ama mütakip end'leri yazmaktan kurtarır.
if op == "+" then r = a + b elseif op == "-" then r = a - b elseif op == "*" then r = a*b elseif op == "/" then r = a/b else error("gecersiz islem") end
Lua 'da switch deyimi olmadığından bu zincirler yaygındır.
while
Klasik olarak Lua ilkin while koşulunu test eder; koşul false ise döngü biter; aksi takdirde Lua döngünün gövdesini yürütür ve işlemi tekrarlar.
local i = 1 while a[i] do print(a[i]) i = i + 1 end
repeat
Koşulu true olduğu sürece repeat-until deyimi gövdesini tekrarlar. Test gövdeden sonra yapılır, bu nedenle gövde daima en az bir kez yürütülür.
-- boş olmayan ilk girdi satırını yazdır
repeat line = os.read() until line ~= "" print(line)
Diğer birçok dilin aksine Lua da döngü içinde bildirilen yerel bir değişkenin kapsamı koşul kısmını da kapsar(Lua 5.1'de yeni özellik):
local sqr = x/2 repeat sqr = (sqr + x/sqr)/2 local error = math.abs(sqr^2 - x) until error < x/10000 -- 'error' hala burada görünür durumda
Sayısal for
for deyiminin iki çeşidi vardır: sayısal for ve kapsamlı for.
sayısal for devamdaki sözdizimine sahiptir:
for var=exp1,exp2,exp3 do <biseyler> end
Bu döngü, var 'ı arttırmak üzere adım olarak exp3 'ü kullanarak exp1'den exp2 'e var'ın her değeri için bişeyleri yürütür. Üçüncü ifade isteğe bağlıdır; olmadığında, Lua adım değeri olarak 1 kullanır. Bu tür döngülerin tipik örneği olarak
for i=1,f(x) do print(i) end for i=10,1,-1 do print(i) end
Üst limit olmadan bir döngü istiyorsanız math.huge sabitini kullanabilirsiniz:
for i=1,math.huge do if (0.3*i^3 - 20*i^2 - 500 >= 0) then print(i) break end end
for döngüsünü iyi kullanmak için öğrenmeniz gereken bazı inceliklere sahiptir. İlk olarak, döngü başlamadan önce üç ifadenin hepsi bir kez değerlendirilir. Örneğin, iki önceki örneğimizde f(x) sırf bir kez çağrıldı. İkincisi, kontrol değişkeni for deyimi tarafından otomatik bildirilen bir yerel değişkendir ve yalnızca döngü içinde görünür. Tipik bir hata, döngü bittikten sonra değişkenin hala var olduğunu varsaymaktır:
for i=1,10 do print(i) end max = i -- tabiki hata! ’i’ burada global
Döngüden sonra kontrol değişkeninin değerine ihtiyacınız varsa (genellikle döngüyü kırdığınızda-break), değerini başka bir değişkene kaydetmeniz gerekir:
-- bir listede bir değeri bul local found = nil for i=1,#a do if a[i] < 0 then found = i -- ’i’'nin değerini kaydet break end end print(found)
Üçüncü olarak, kontrol değişkeninin değerini asla değiştirmemelisiniz: bu tür değişikliklerin etkisi tahmin edilemez. Normal sondan önce bir for döngüsünü bitirmek istiyorsanız, break 'i kullanın (önceki örnekte yaptığımız gibi).
Kapsamlı for
Kapsamlı for döngüsü bir iteratör fonksiyon ile döndürülen tüm değerleri dolaşır.
-- 'a' dizisinin tüm değerlerini yaz for i,v in ipairs(a) do print(v) end
Temel Lua kütüphanesi bir diziyi dolaşmak için kullanışlı bir yineleyici(itaratör) fonksiyon olan ipairs i sağlar. Bu döngüdeki her adımda, i, indeksi v'de bu indeksle ilişkilendirilmiş değeri alır. Benzer bir örnek, bir tablonun tüm anahtarlarını nasıl dolaşılacağını göstermekte:
-- ’t’ tablosunun tüm anahtarlarını yazdır for k in pairs(t) do print(k) end
Belirgin basitliğine rağmen kapsamlı for güçlüdür. Doğru iteratörlerle hemen hemen her şeyi okunabilir modda dolaşabiliriz. Standart kütüphaneler, bir dosyanın satırlarını(io.lines), tablo çiftlerini (pairs), dizi girdilerini(ipairs), string kelimelerini(string.gmatch) vb. gezmemize imkan veren çeşitli itaratörler sağlamıştır. Tabii ki kendi iteratörlerimizi yazabiliriz. kapsamlı for kullanımı kolay olmasına rağmen iteratör fonksiyonları yazmanın incelikleri vardır. Bu konuyu daha sonra bölüm 7'de ele alacağız.
Kapsamlı döngü sayısal döngü ile iki özelliği paylaşır: döngü değişkenleri döngü gövdesine yereldir ve onlara hiçbir zaman herhangi bir değer atamamalısınız.
Kapsamlı for kullanımı için daha somut bir örnek görelim. hafta günlerinin isimleriyle bir tablonuz olduğunu varsayalım:
gunler = {"Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"}
Şimdi isminden konumunu çevirmek istiyorsunuz. Verilen ada bakarak tabloyu arayabilirsiniz. Ancak çoğu zaman Lua 'da daha verimli bir yaklaşım ters tablo oluşturmaktır, tersineGunler adındaki bu tablo indeksler olarak isim ve değerler olarak sayılara sahiptir. Bu tablo şöyle:
tersineGunler = {["Pazar"] = 1, ["Pazartesi"] = 2, ["Salı"] = 3, ["Çarşamba"] = 4, ["Perşembe"] = 5, ["Cuma"] = 6, ["Cumartesi"] = 7}
Daha sonra yapmanız gereken tek şey ters tabloyu indeksleyen ismin sırasını bulmak :
x = "Salı" print(tersineGunler[x]) --> 3
Tabii ki ters tabloyu manuel yazıp beyan etmemize gerek yoktur. Orjinalinden otomatik olarak inşa edebiliriz:
tersineGunler = {} for k,v in pairs(gunler) do tersineGunler[v] = k end
Üsteki döngü her gün öğesi için atama yapar, k değişkeni (1, 2, . . .) anahtarı , v (“Pazar”, “Pazartesi”, . . .) değerlerini alır
4.4 break ve return
break ve return deyimleri bloktan çıkmamıza imkan verir.
Bir döngüyü bitirmek için break deyimini kullanıyoruz. Bu deyim onu içeren döngüyü(for, repeat veya while) keser; bir döngünün dışında kullanılamaz. break'den sonra program kırılan döngüden hemen sonraki noktadan çalışmaya devam eder.
return deyimi bazen fonksiyondan sonuçlar döndürmek bazende sadece bir fonksiyonu bitirmek için kullanılır. Her fonksiyonun sonunda örtülü bir return vardır bu nedenle eğer döndürülen herhangi bir değer yoksa return kullanma zorunluluğu olmadan fonksiyonunuz kendiliğinden biter.
Sözdizimsel olarak break veya return bir bloğun son ifadesi olabilir; Başka bir ifadeyle öbeğinizdeki son deyim olarak veya end , else veya until 'den hemen önce. Örneğin bir sonraki örnekte break , then bloğunun son deyimidir.
local i = 1 while a[i] do if a[i] == v then break end i = i + 1 end
bu deyimleri bu yerlerde kullanılmasıyla takip eden başka herhangi bir deyim ulaşılamaz olur. Bazen tabi bir blok ortasında return ya da break yazmak yararlı olabilir; örneğin fonksiyonun yürütmesinden kaçınıp hata ayıklama işletmek isteyebilirsiniz. Bu gibi durumlarda devamdaki gibi deyim etrafında do bloğu kullanabilirsiniz:
function foo () return --<< sözdizimi hatası -- ’return’ aktif bloktaki(fonksiyon bloğu) son deyim olmalıdır do return end -- okey <diger deyimler> end
Hiç yorum yok:
Yorum Gönder