4 Deyimler

4 Deyimler

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