3 İfadeler

3 İfadeler

İfadeler, değerleri sağlar. Sayısal sabitler , stringler, değişkenler, tekli-ikili işlemler ve fonksiyon çağrıları Lua'da ifadeler kapsamındadır. İfadeler aynı zamanda pek alışıldık olmayan fonksiyon tanımlamaları ve tablo oluşturucularını da kapsar.

3.1 Aritmetik Operatörler

Lua geleneksel aritmetik operatörleri destekler: ikili; '+' (toplama), '-' (çıkarma), '*'(çarpma),  '/'(bölme), '^'(üs), '%' (mod) (mod operatörü Lua 5.1 'de yeni), ve tekli; '-' (negatif). Tümü gerçek sayılar üzerinde çalışır. Örneğin  x^0.5, x'in karekökünü hesaplar, x^(-1/3) , x'in küpkökünün tersini hesaplar.

Mod operatörü devamdaki kurala göre tanımlanıktır:

a % b == a - math.floor(a/b)*b

Tamsayı argümanlar için sonuç normal olarak daima ikinci argümanı ile aynı işarete sahiptir. 
 
Gerçek sayı argümanlarda birkaç ekstra kullanım alanı var. Örneğin  x%1, x'in ondalık kısmıdır dolayısıyla x-x%1, x'in tamsayı kısmıdır. Benzer şekilde x-x%0.01,  sadece iki ondalık basamaklı x'dir:

x = math.pi
print(x - x % 0.01) --> 3.14

mod operatörünün başka bir kullanım  örneği olarak, verilen bir açıyla döndürülen bir aracın aynı yoldan geriye dönüp dönmeyeceğini kontrol etmek istediğinizi varsayalım. Açı derece olarak verilirse aşağıdaki formülü kullanabilirsiniz:

local tolerans = 10
function donermi(aci)
    aci = aci % 360
    return (math.abs(aci - 180) < tolerans)
end


Bu tanımlama negatif açılar için de çalışır:

print(donermi(-180))      --> true

Derece yerine radyanla çalışmak istiyorsak fonksiyonumuzdaki sabitleri basitçe değiştiririz:

local tolerans = 0.17
function donermi(aci)
    aci = aci % (2 * math.pi)
    return (math.abs(aci - math.pi) < tolerans)
end

aci % (2*math.pi) işlemi sadece açıyı [0,2π) aralığında bir değere normalleştirme ihtiyacı içindir.

3.2 İlişkisel operatörler

Lua devamdaki ilişkisel operatörleri sunar:

< > <= >= == ~=

Tüm bu operatörler daima true veya false ile sonuçlanır.

== operatörü eşitliği test eder; ~= operatörü eşitsizliği.
iki operatörü herhangi iki değere uygulayabilirsiniz. Değerler farklı tipte ise Lua onları eşit değildir diye dikkate alır. Aksi halde Lua  onları tiplerini dikkate alarak karşılaştırır . Özellikle belirtelim nil sadece kendisine eşittir.

Lua, referansıyla fonksiyonları , tabloları, kullanıcı versini karşılaştırır diğer bir deyişle  iki değer yalnızca aynı nesne ise eşit olarak kabul edilir. Örneğin şu koddan sonra

a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
c = a

a==c ama a~=b 'e sahip olursunuz.

Büyüklük operatörlerini yalnızca iki sayıya veya iki stringe uygulayabiliriz. Lua, yerelleştirme ayarını takip ederek alfabetik düzende stringleri karşılaştırır. Örneğin European Latin-1 yerelleştirme ayarında "acai"<"açaı"<"acorde" 'dir. Sayılar ve stringler dışındaki değerler yalnızca eşitlik(ve eşitsizlik) için karşılaştırılabilir.

Farklı tipteki değerleri karşılaştırırken dikkatli olmalısınız: "0" 'ın 0'dan farklı olduğunu unutmayın.
 2<15 true ancak "2"<"15" false 'dir(alfabetik düzende). Aykırı sonuçlardan kaçınmak için Lua string ve sayıların birbiriyle büyüklük karıştırması yaptığınız da (2<"15" gibi) hata yükseltir.

3.3 Mantıksal operatörler

Mantıksal operatörler  and, or ve not 'dır. Kontrol yapıları gibi tüm mantıksal operatörler false nil ikilisini false ve diğer herhangi bir şeyi true olarak dikkate alır. and işlemi false ise ilk argümanını döndürür; aksi takdirde ikinci argümanını döndürür. or işlemi false değilse ilk argümanını döndürür; aksi takdirde ikinci argümanını döndürür:

print(4 and 5)      --> 5
print(nil and 13)   --> nil
print(false and 13) --> false
print(4 or 5)       --> 4
print(false or 5)   --> 5

Hem and hem de or kestirme değerlendirme kullanır yani ikinci değerlendirmeye gerekirse gidilir.
(type(v)=="table" and v.tag=="h1") gibi bir ifade de kestirme değerlendirme yapılması çalışma zamanı hatasına götürmekten kurtarır. (Lua v bir tablo olmadığında v.tag  'ı değerlendirmeye girişmeyecek.)

Kullanışlı bir Lua kalıbı olan x = x or v  devamdakine eşdeğerdir:

if not x then x = v end

Yani x 'e değer set edilik olmadığında(x'e false değeri set edildiğinde de) v varsayılan değeri x'e set edilir .

Diğer bir kullanışlı kalıp, (a and b) or c (basitçe a and b or c çünkü and or'dan daha yüksek önceliğe sahiptir) , b'nin false olarak set edilmemiş olması koşuluyla C dilindeki a?b:c ifadesine denktir.
Örneğin devamdaki gibi bir ifadeyle x ve y 'den en büyük olanını seçebilirsiniz:

max = (x > y) and x or y

x>y olduğu zaman and 'in ilk ifadesi true 'dur böylece and daima true olan(çünkü o bir sayı) ikinci ifadesinde(x) sonuçlanır ve sonra or ifadesi ilk ifadesinin(x) değerinde sonuçlanır.
x>y false olduğu zaman and ifadesi false 'dir böylece or ikinci ifadesinde(y) sonuçlanır.

not operatörü daima true veya false döndürür.

print(not nil)      --> true
print(not false)    --> true
print(not 0)        --> false
print(not (not nil))--> false

3.4 Birleştirme

Lua,  .. operatörüyle(iki nokta) string birleştirmesi sağlar, işlenenlerden herhangi biri sayı ise Lua bu sayıyı string'e çevirir.

print("Merhaba " .. "Dünya")--> Merhaba Dünya
print(0 .. 1)               --> 01

Lua 'da string değerleri değişmez unutma. Birleştirme operatörü işlenenlerde herhangi bir değişiklik yapmadan daima yeni bir string oluşturur:

a = "Merhaba"
print(a .. " Dünya")--> Merhaba Dünya
print(a)            --> Merhaba

3.5 Öncelikler

Lua 'da operatör öncelikleri devamdaki tabloda yüksekten düşüğe şekilde verilmiştir:

^
not                #                     - (tekli)
*                   /                      %
+                  -
..
<                  >                    <=                  >=                     ~=                 ==
and
or

sağ ilişkisel olan '^'(üs) ve '..'(birleştirme) hariç tüm ikili operatörler sol ilişkiseldir. Devamdaki soldaki  ifadeler ile sağdaki ifadeler eşdeğerdir:

a+i < b/2+1 <--> (a+i) < ((b/2)+1)
5+x^2*8 <-->          5+((x^2)*8)
a < y and y <= z <-->          (a < y) and (y <= z)
-x^2 <-->         -(x^2)
x^y^z <-->          x^(y^z)


Şüpheniz olduğunda her zaman parantez kullanın. Kitaba bakmaktan daha kolay ve koda daha sonra tekrar baktığınızda muhtemelen yine şüpheye düşeceksiniz.

3.6 Tablo Oluşturucular

Oluşturucular , tabloları oluşturup ilkleyen ifadelerdir. Lua'nın ayırt edici özelliklerinden biri ve en kullanışlı ve çok yönlü mekanizmalarından biridir. En basit oluşturucu boş oluşturucu, {}, boş bir tablo yaratır; Daha önce görmüştük. Oluşturucular aynı zamanda dizileri(listeler veya seriler olarak da isimlendirilirler) ilkler. Örneğin şu deyim

gunler = {"Pazar", "Pazartesi", "Salı", "Çarşamba",
        "Perşembe", "Cuma", "Cumartesi"}

gunler[1]'i "Pazar" string ile ilkleyecek(oluşturucunun ilk öğesi indeks 1 'e sahiptir, 0 değil),
gunler[2]'i "Pazartesi" string ile ilkleyecek ve bu şekilde gidecek.

print(gunler[4])               --> Çarşamba

Lua, bir sonraki örnekte olduğu gibi kayıt(record) tarzı bir tablo ilklemek için özel bir sözdizimi de sunar:

a = {x=10, y=20}

önceki satır devamdaki şu komutlara eşdeğerdir:

a = {}; a.x=10; a.y=20

Bir tablo oluşturma için kullandığımız oluşturucunun ne olduğunun önemi olmadan daima alanlar ekleme ve çıkarma yapabiliriz:

w = {x = 0, y = 0, label = "console"}
x = {math.sin(0), math.sin(1), math.sin(2)}
w[1] = "diğer alan" -- ’w’ tablosuna 1 anahtarını ekle
x.f = w             -- ’x’ tablosuna "f" keyini ekle
print(w["x"])       --> 0
print(w[1])         --> diğer alan
print(x.f[1])       --> diğer alan
w.x = nil           -- "x" alanını çıkar

Yani tüm tablolar aynı yaratılır; oluşturucular yalnızca ilklemeyi etkiler.

Lua bir oluşturucuyu her değerlendirdiğinde yeni bir tablo yaratır ve ilkler.

Dolayısıyla bağlı listeleri(linked list) uygulamak için tabloları kullanabiliriz:

list = nil
for line in io.lines() do
    list = {next = list, value = line}
end

Bu kod standart girdiden satırları okur ve bunları ters sırada bağlı listede saklar. Listedeki her düğüm(node) iki alanlı bir tablodur: value satırın içeriği, next sonraki düğüme referans. Aşağıdaki kod listeyi dolaşır ve içeriğini yazdırır:

local l = list
while l do
    print(l.value)
    l = l.next
end

(Listemizi bir yığın(stack) olarak uyguladığımız için satırlar ters sırada yazdırılacaktır.) Öğretici olmasına rağmen yukarıdaki uygulamayı gerçek Lua programlarında nadiren kullanırız; 11. bölümde göreceğimiz üzere listeler diziler olarak daha iyi uygulanmaktadır.

Aynı oluşturucuda liste-stili ve record-stili ilkleyicileri  miksleyebiliriz.

polyline = {color="blue", thickness=2, npoints=4,
            {x=0, y=0},
            {x=-10, y=0},
            {x=-10, y=1},
            {x=0, y=1}
            }

Yukarıdaki örnek ayrıca daha karmaşık veri yapılarını temsil etmek için oluşturucuları nasıl iç içe yerleştirebileceğimizi de göstermekte. polyline[i] öğelerinin her biri bir kayıdı-record temsil eden bir tablodur:

print(polyline[2].x) --> -10
print(polyline[4].y) --> 1

Bu iki oluşturucu formu için sınırlamalar var. Mesela alanları negatif indekslerle veya uygun olmayan string indeksleriyle ilkleyemezsiniz. Bu tür ihtiyaçlar için başka daha genel bir format var. Bu formatta, bir ifade olarak ilklenecek indeksi köşeli parantezler arasında yazarız:

islemIsimleri = {["+"] = "toplama", ["-"] = "cikarma",
                ["*"] = "carpma", ["/"] = "bolme"}

i = 20; s = "-"
a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}

print(islemIsimleri[s])                             --> cikarma
print(a[22])                                        --> ---


Bu sözdizimi daha külfetli ancak daha esnek: liste stili ve kayıt stili form ikilisi bu daha genel sözdiziminin özel durumlarıdır. {x=0,y=0} oluşturucusu {["x"]=0,["y"]=0} 'e denktir ve {"kirmizi","yesil","mavi"} oluşturucusu  {[1]="kirmizi",[2]="yesil",[3]="mavi"} 'e denktir.

0'dan başlayan diziler isteyenler için aşağıdakileri yazmak çok zor değil:

gunler = {[0]="Pazar", "Pazartesi", "Salı", "Çarşamba",
            "Perşembe", "Cuma", "Cumartesi"}

Artık ilk değerimiz "Pazar" 0 indeksinde. Bu sıfır diğer alanları etkilemez; "Pazartesi" doğal olarak indeks 1'e gider oluşturucuda birinci liste değeri olduğundan; diğer değerler onu takip eder.
Bu imkana rağmen Lua'da 0'dan başlayan diziler kullanılmasını önermiyorum. Çoğu Lua fonksiyonu dizilerin 1 indeksinden başladığını varsayar ve bu nedenle bu tür diziler doğru bir şekilde ele alınamazlar.

Son girdiden sonra  bir virgül koyabilirsiniz daima. Bu sondaki virgül isteğe bağlıdır ancak  geçerlidir daima:

a = {[1]="kırmızı", [2]="yeşil", [3]="mavi",}

Bu esneklik Lua tabloları üreten programların  özel bir durum olarak son öğeyi ele almasını gerektirmez.

Son olarak,  bir oluşturucuda virgül yerine noktalı virgül de kullanabilirsiniz daima.
Bir oluşturucuda farklı bölümlerin sınırlarını belirtmek için genellikle noktalı virgülle ayrılır, örneğin kayıt bölümünü(anahtar-değer), liste bölümünden ayırmak için:

{x=10, y=45; "bir", "iki", "uc"}



Hiç yorum yok:

Yorum Gönder