Merhaba, 3. bölümde sınıflarda kalıtım sistemi ile devam ediyoruz.
Sınıflarda kalıtım
-- Deyim yapısı
-- Alt sınıflar
Kalıtım ile bir sınıftan ilave ya da değişmiş özellikleri olan bir alt sınıf üretilir.
Bu örnekte Köpek sınıfı Hayvan sınıfından kalıtımla üretilmiş bir alt sınıftır.
Köpek sınıfı merhaba_de ve ye metodlarını Hayvan sınıfından kalıtımla alır.
Köpek sınıfı tanımında merhaba_de metodu üzerine yazılarak Hayvan sınıfına göre davranışı değiştirilmiştir.
-- Çoklu kalıtım
Ruby birkaç sınıftan alt sınıf oluşturmayı yapan çoklu kalıtımı desteklemez (bir sınıfın tek ebeveyni olur). Ancak modüller kullanarak ve bunları sınıflarda içererek karmaşık sınıflar oluşturulabilir. Bir örneğini burada yazmıştım.
-- Kalıtmla ne geçer
-- -- Metodlar kalıtımla geçer
-- -- Sınıf metodları da kalıtımla geçer
-- -- Sabitler kalıtımla geçer
Ama dikkat edin üzerlerine yazılabilir.
-- -- Oluşum değişkenleri kalıtımla geçer
Şu noktaya dikkat edin, eğer oluşum değişkenine ilk değeri veren metodun üstüne yazarsanız, ve değer de vermezseniz, oluşum değişkeni nil değeri olur. Yukarıdaki koda devam edelim.
-- -- Sınıf oluşum değişkenleri kalıtımla geçmez
Zaten sınıf oluşum değişkeninin yapılma amacı da bu olabilir, alt sınıflarına (çocuklarına) geçmez.
-- -- Sınıf değişkenleri gerçekte kalıtımla geçmez
Sınıf değişkenleri ana sınıf ve tüm yavru sınıflarda tek bir değişkenmiş gibi paylaşılır.
-- Mixin'ler
Mixin çoklu kalıtıma benzer etki elde etmek için en doğru yoldur. Modüller içindeki metodları sınıflarımıza aynı kalıtımla üst sınıf metodlarını aldığımız gibi alabiliriz. Bu metodlar oluşum ya da sınıf metodu olarak kullanılabilir. Aşağıdaki örnek bunu tasvir ediyor.
-- Mevcut sınıfları kalıtım kullanacak şekilde düzenlemek
Diyelim Kedi ve Köpek adlarında iki sınıfımız olsun.
Bu iki sınıfta ye metodu aynı davranışı gösteriyor. Eğer aynı metodu kullanan bir sürü sınıfımız olsa durum daha da vahim olur. Bunu kalıtımla çözebiliriz.
Ortak metodumuzu içeren bir Hayvan sınıfı ürettik sonra da Kedi ve Köpek sınıflarını buradan kalıtımla üretince ikisinde de metodumuz kullanılabilir.
Akış Kontrolleri
-- if elsif else ve end
Ruby bütün programlama dillerinde olan if...else dallanma yapılarını if - elsif - else - end ifadeleri ile gerçekleştirir.
Ruby'de if yapıları işlem yapan ifadelerdir, bloktan dönen değer kullanılabilir.
Dönen değer bloktan çıkmadan önce son elde edilen değerdir.
Burada yaş değeri ne olursa olsun ya :ufaklık ya :yetişkin değeri durum değişkenine atanır. :boo ve :foo değerleri bloktan çıkmadan önce son işlenen satırlar olmadığı için, hiç bir zaman durum değişkenine atanmaz.
-- -- Ternary operatör
Ruby ayrıca Ternary operatörü de destekler.
Ternary operatör yapısında bir_ifade ile belirtilen ifadenin sonucu true çıkarsa soru işaretinden sonra gelen işlem, false çıkarsa iki nokta sonrasındaki işlem gerçekleştirilir. Bu doğrultuda yukarıdaki if...else bloğu yerine.
şeklinde tek satır yazılabilir.
İlave olarak elsif ifadesi ile extra karşılaştırmalar da yapabiiriz.
if koşulu gerçekleşmezse ilk elsif (elseif değil dikkat edelim) koşuluna bakılır, o da gerçekleşmezse ikinci elsif koşuluna bakılır, hiç bir koşul gerçekleşmezse else ile verilen değer geri döner.
Eğer else ifadesini koymadıysak ve hiç bir koşul gerçekleşmezse nil değer dönecektir. Bu string enterpolasyonunda çok işe yarar, nil.to_s bize boş bir string verir.
gibi.
-- case ifadesi
Ruby switch yapıları için case deyimini kullanır.
Ruby dökümanına göre, case ifadeleri isteğe bağlı bir koşul (bu koşul case deyimine argüman gibi verilir), ve bir ya da daha çok when maddelerinden oluşur. Sırayla giderken hangi when maddesi koşulu karşılarsa (ya da koşul verilmemişse boolean doğru sonuç veren bir işlem olursa), ona ait kod bölümü çalıştırılır. case yapısından dönen değer, koşulu karşılayan when kısmından dönen değer olur ya da koşul karşılanmazsa nil döner.
Bir case yapısı else bölümüyle bitebilir. Her when satırı virgülle ayrılmış bir'den çok aday değere sahip olabilir.
Bunun kısaltılmış yazımı.
Aslında daha az şey yazmadık , ama az satır kullandık, pek de kısaltılmış değil.
Bir de case'e koşul vermeden deneme yapalım.
Tamamen farklı çalışan iki farklı yöntem gibi duruyor. Her biri başka amaçla kullanılabilir.
case'e verilen değer karşılaştırılırken == değil === kullanıldığı için birçok ilginç kullanım imkanları oluşur.
Bir case yapısı Range nesnelerle kullanılabilir.
Regexp ile kullanılabilir.
Proc veya lambda ile de kullanılabilir.
Sınıflar'la da kullanılabilir.
=== operatörü kullanarak kendi eşleşmelerinizi üretebilirsiniz.
Bir case yapısı argüman girmeden de çelışabilir.
case yapısının dönen değeri vardır, bu sayede metodlara argüman olarak verilebilir veya bir değişkene atanabilir.
-- Doğru ve yanlış değerler
Ruby'de sadece iki değer yanlış kabul edilir.
- nil
- boolean false
Tüm diğer değerler doğru kabul edilir, içinde şunlar da var:
- 0 - tamsayı ya da diğer tiplerde.
- "" - Boş string
- "\n" - harf içermeyen stringler
- [ ] - Boş array
- { } - Boş hash
Örneğin aşağıdaki kodu alalım.
çıktımız şöyle olur:
-- Satır içinde if/unless
Satır içinde veya takipçi if veya unless kullanmanın genel şablonu.
Buna koşullu değiştirici denir, ve koruma önlemi kodları yazarken ve kod kısaltırken çok işe yarar.
Bu değiştiricilere else bölümü ekleyemeyiz. Bir de koşullu değiştiricileri esas işi yapan kod bloklarında kullanmak önerilmez, karmaşık kodlarda if..elsif..else..end blokları önerilir.
-- while ve until döngüleri
Bir while döngüsü verilen koşul true olduğu sürece blok içinde verilen kodları tekrar tekrar çalıştırır.
while satırında koşul karşılanırsa blok içindeki kod çalıştırılır, eğer koşul doğru değilse blok kodu çalıştırılmadan end sonrasına geçilir. Blok kodu çalışıp end satırına geldiyse tekrar while satırına gönderilir, böylece koşul karşılanana kadar aynı kod döner durur.
until döngüsü ise tam tersine verilen koşul false olduğunda blok kodunu çalıştırır.
Yalnız böyle tek bir değeri bekleyen kodlarda dikkat etmek lazım, i değeri 6'dan falan başlatılırsa sonsuza kadar kod döner.
-- Veya eşitlemesi (koşullu atama)
Ruby veya eşitlemesi operatörü , bir değişkene eğer değeri sadece nil veya false ise başka bir değer atamak için kullanılır.
Sanki += operatörü falan gibi düşünsek bunun da eşitliğin solu ile sağını veya işlemine tabi tutup soluna yazacağını düşünebiliriz.
Aslında öyle değil daha çok
şeklinde gösterilebilir. x değeri nil ya da false değil ise zaten or işleminin sol tarafı true olacağı için, sağ tarafa bakılmaz bile, ve x aynı kalır. Eğer x değeri false ya da nil ise or işleminin sol tarafı false vereceğinden sağ tarafına geçilir, orası da x değişkenine y değerini atar.
Bu veya eşitlemesi bir şeylerin değerinin olmadığı yerlerde diğer bir değer kullanmak için çok kullanılır. Diyelim kullanıcıya mail atacaksınız ama o kullanıcıda tanımlı bir email yok, yerine kendinize mail atabilirsiniz.
bu kodu tek satırda bitirmek mümkün.
aynı işi yapar.
false değerinin geçerli bir değer olduğu durumlarda bu operatörü kullanmak sorun oluşturabilir.
-- Ruby flip flop operatörü
Bu ilginç bir operatör önce kaldırılacağı duyuruldu, sonra tekrar geri geldi vs.
Flip flop operatörü . . iki koşul arasında yerleştirilir.
Koşul ilk karşılaştırma, iterasyonda true değer verene kadar false sonuç verir ve işlem yapılmaz. Sonra true sonuç verir ve ikinci koşul true değer verene kadar öyle kalır, sonra tekrar false olur.
Bu örnek nelerin seçildiğini gösteriyor.
Flip flop operatörü sadece if'lerde (unless da dahil) ve ternary operatörlerde çalışır. Diğer yerlerde görüntüden de anlaşılacağı gibi Range nesnesi gibi görülür.
İterasyon içinde true ve false sonuçlarına defalarca ulaşabilir.
-- throw ve catch
Diğer programlama dillerinden farklı olarak Ruby'de throw ve catch sıradışı durumları işlemek için kullanılan deyimler değildir.
Ruby throw ve catch deyimleri biraz diğer dillerdeki label kullanımına benzer. Akışı değiştirmek için kullanılır ama sıradışı durumlarda hata algılamakla alakalı değildir.
İç içe bloklar var. throw deyimi parametresinde verilen catch bloğunu bulur ve onun dışına çıkar. İç içe bloklardan çıkmak için break kullanıp iki bloktan da çıkmak için koşullar oluşturmak yerine throw kullanmak faydalı olacaktır.
burada sadece ilk iç döngüden çıkılacağı için sonraki r değerleri de değerlendirilecektir.
Ama throw kullanarak iki döngüden de çıkabiliriz.
ve çıktısı
Bu da ilginç bir sıçrama komutu olarak hafızamızda yerini alsın.
-- unless deyimi
Eğer birşeylerin olmadığı koşullarda iş yapmak istersek genelde if !(bir_koşul) şeklinde değilini kullanırız. Ruby kod okunurluğu bakımından daha iyi duran bir alternatif olarak unless deyimini kullanır.
Yapı aynı if deyimi yapısı gibidir, ve satır içi koşullarda da kullanılır. unless yapısında elsif gibi ikinci bir karşılaştırma yapma imkanı yoktur, fakat else satırı olabilir.
-- Ternary operatör
Ruby'de de ternary operatörü ( ? : ) kullanımı vardır. Bir koşul sorgulanır, doğruysa bir işlem , yanlışsa başka bir işlem yapılır.
Prensip olarak if a then b else c end yazmaya benzer. Örnek
-- break, next ve redo ile döngülerde dallanma
Bir Ruby kod bloğunun akışı break, next ve redo deyimleri kullanarak değiştirilebilir.
-- -- break
break komutu ile hemen içinde bulunulan kod bloğu sonlandırılır. Komut sonrasında olan satırlar işlenmez, döngü varsa döngü de biter, yani end satırı arkasına atlanır diyebiliriz.
-- -- next
next deyimi bir iterasyon içinde kullanıldığında hemen bloğun başına döner ve sonraki iterasyona geçer. Bu da sanki end satırına atlıyormuş gibi düşünülebilir.
Döngü olmayan blokta next kullanırsak hata verir.
-- -- redo
redo ile blok başına dönülüp aynı iterasyon tekrar yapılır.
Dikkatli olun , bu döngü kendi kontrolümüzde ve index sayacını biz kendimiz arttırıyoruz. Bu örnekte index += 1satırının redo sonrasında konması sayesinde aynı iterasyon tekrarlanmıştır.
Bu kodun davranışı bambaşka olur, dikkat edelim.
-- -- Enumerable iterasyonları
Döngüler dışında bu dallanmalar each ve map gibi enumerable iterasyonlarında da kullanılır.
-- -- Blok dönen değerleri ne olur?
Hem break hem de next deyimlerine bir değer eklenerek dönen değer olarak kullanılabilir.
Kitaptan bir örnek verelim.
yerine
yazılabilir. Ama bir de bu var.
Ternary sanki daha iyi bir ifade. next sonrasında değer girmek Ruby'nin meşhur İngilizce cümle gibi okunurluğu özelliğine pek uymamış sanki.
-- return ve next - bloktan yerel olmayan dönüş
Şu yarıda kesilen kod parçacığına bakalım.
İlk bakışta sanki iterasyon sonucunda işlenmiş değerler dönecekmiş gibi geliyor. [1, 0, 3, 0] gibi bir değer beklenirken, return aslında metoddan geri dönüyor ve değeri sıfır oluyor. Dikkat ederseniz 'baz' yazısı hiç yazılmaz, çünkü kod oraya asla ulaşamadan metod biter.
Ama next burada işimizi görür çünkü blok seviyesinde değer döner ve beklenen sonuç alınır.
return satırı konmadığında metodlardan dönen değer en son hesaplanan değerdir. Bu örnekte de end satırı öncesine yazılan bar değişkeni değeri metoddan dönen değerdir.
-- Akışı lojik işlemlerle yönetmek
Her ne kadar mantığa aykırı gibi gelse de mantıksal işlemleri prosesleri yönetmek amacıyla kullanabilirsiniz. Örneğin.
or işlemi iki tarafından birinin true değer vermesi durumunda true değer döner. Ruby bunu yapmak için ilk önce deyimin sol tarafına bakar ve oranın true sonuç verip vermediğine bakar. Deyimin solunda File.exist?(dosya_adı) yazıyor, ve eğer ismi verilen dosya mevcutsa bu işlem true dönecektir. Eğer sol taraf true değer dönerse Ruby sağ tarafa bakmaz bile ve çünkü or işleminin gereği olan en az bir tarafın true olması koşulu gerçekleşmiş olur. Ama eğer dosya mevcut değilse deyimin sol tarafı false olacağından , sağ tarafındaki işlemin sonucuna bakılır. E bakmak içinde o işlemi çalıştırması gerekir, ve böylece ekrana hata mesajı yazılmış olur. Sağ tarafın sonucunun true olup olmaması bizi ilgilendirmiyor, biz or deyimini sadece bir işlem başarısız olursa diğerini yapalım amacıyla kullandık.
or deyiminin dallanma amaçlı bir yaygın kullanımı da şöyledir.
bardak değişkenine henüz bir değer girilmemişse "dolu" değerini verir.
Yukarıdaki ifade genelde Ruby'ciler tarafından,
şeklinde kullanılır, onu da söyleyelim.
or gibi and deyimi de dallanma amaçlı kullanılabilir.
Burada da eğer bir şey gerçekleşirse ikinci şeyi yapmak için and deyimi kullanılıyor. and deyimi her iki tarafının da sonucu true olursa true çıkış verir. Bunu yaparken de ilk önce sol tarafın sonucunu bulur, yani örnekte dosya_adı ile verilen dosya mevcut mu, test eder. Dosya yoksa zaten sol taraf false döndüğü için sağ tarafa bakılmaz bile işlem sonucu false olur. Ama dosya mevcutsa, sol taraf true değer döndüğü için sağ taraftaki işlem de yapılır ve ekrana dosyanın bulunduğu yazılır. Tabi ki yine and işlemi sonucuyla ilgilenilmez.
or işlemi and işleminden daha düşük önceliklidir. Aynı şekil || işlemi de && işleminden düşük önceliklidir, ve sembol şekillleri yazı şekilllerinden daha önceliklidir. Bütün bunları göz önünde bulundurarak karışık teknikler geliştirebiliriz.
Bu kullanımlarla programı inceleyen başka yazılımcıların kafasını bulandırabiliriz, ancak Ruby Style Guide şöyle der:
and ve or kelimelerini mümkünse kullanmayın , okunurluğu arttırırken ince hatalar yapmanıza sebep olabilir. Boolean işlemler için her zaman || ve && kullanmaya özen gösterin. Akış kontrolü için if ve unless kullanın, || ve && de kullanabilirsiniz ancak okunurluğu düşük olur.
-- begin , end blokları
begin bloğu birçok satırdan oluşan bir kısım kodu bir arada toplamak için kullanılır.
begin bloğu son edinilen değeri geri döner. Aşağıdaki örnekte blok 3 değeri döner.
begin bloğu ||= operatörü kullanarak yapılan değer atamalarında birkaç satır kodun sonucunu hesaplamak için çok kullanışlıdır.
begin blokları rescue, ensure, while, if, unless gibi bloklarla beraber kullanılarak program akışını kontrole yardımcı olurlar.
begin blokları {...} ve do...end kod blokları gibi değildir. Metodlara gönderilemezler.
Bu bölümü de burada bitirelim , sonraki bölümde String değerler ile devam edeceğiz inşallah.
Şimdilik kalın sağlıcakla..
Hiç yorum yok:
Yorum Gönder