Bu yazıda Java’ya benzeyen ancak Java programlama dilinin tuzaklarını/eksiklerini gidermek için tasarlandığı için çok daha fazla gelişmeye sahip olan Scala Programlama dili ile nasıl çalışılacağını göreceğiz.
Wikipedia’ya göre Scala Programlama dilinin tanımı şu şekildedir.
Scala genel amaçlı bir programlama dilidir. Scala, işlevsel programlama için tam desteğe ve çok güçlü bir statik tip sisteme sahiptir. Kısa olması için tasarlanan Scala’nın tasarım kararlarının çoğu, Java’nın eksikliklerine yönelik eleştirilerden ilham aldı.
Scala kaynak kodunun Java bayt koduna derlenmesi amaçlanmıştır, böylece ortaya çıkan yürütülebilir kod bir Java sanal makinesinde çalışır. Java kitaplıkları doğrudan Scala kodunda kullanılabilir ve bunun tersi de geçerlidir (dil birlikte çalışabilirliği). Java gibi, Scala da nesne yönelimlidir ve C programlama dilini anımsatan küme parantezli bir sözdizimi kullanır. Java’dan farklı olarak Scala, Scheme, Standard ML ve Haskell gibi işlevsel programlama dillerinin currying, type inference, immutability, lazy evaluation, and pattern matching gibi birçok özelliğine sahiptir.
Çevre
Bu makaledeki örnekler Komut İstemi / Kabuk’ta Scala Yorumlayıcı ile yürütülmektedir. Ancak, ilgili eklentiler aracılığıyla herhangi bir IDE (Eclipse – Scala IDE, IntelliJ IDEA vb. gibi) ile çalışacakları garanti edilir. Örnekler, Windows 7’de Scala Sürümü: 2.11.7 ile yürütülür.
Öncelikle Scala’yı masaüstümüze indirip kuralım. İşletim Sisteminiz için Scala’nın en son sürümünü indirmek için lütfen bu bağlantıya bakın. Diğer yürütülebilir dosyalar gibi basit bir kurulumdur. Varsa İşletim Sisteminiz için yönergeleri takip edebilirsiniz. Bu, Scala programlarıyla çalışmaya başlamamız için Scala’nın %SCALA_HOME%/bin dizinini PATH ortam değişkenine ayarlayacaktır.
Scala’da Merhaba Dünya
Scala’da tipik, popüler Hello, World’ü görmek için biraz Scala kodu yazalım. Bunu yapmanın iki yolu var. Birincisi, bir REPL olan Scala Yorumlayıcı, diğeri ise kodu bir dosyaya kaydetmenin ve daha sonra derleyip yürütmenin olağan yoludur. İkisini de burada göreceğiz.
REPL Yorumlayıcı ile Merhaba Dünya
Scala Interpreter, C, C++ ve Java gibi birkaç programlama dilinde olduğu gibi, herhangi bir temel sınıf yapısı olmadan, eşlik eden bir barebone iskeleti olarak hızlı satırları ve komut dosyalarını çalıştırabileceğiniz bir REPL (Okuma-Değerlendirme-Baskı-Döngüsü) Yorumlayıcısıdır. . Bu, programlama dilini ve yapılarını değerlendirmek için bir avantajdır, böylece zamandan tasarruf edebilirsiniz. Anlık sonuçlarınız için bu REPL yorumlayıcısını kullanırsınız.
İki kat emin olmak için, %SCALA_HOME% ortam değişkenini görerek Scala’nın makinemize doğru kurulup kurulmadığını doğrulayalım.
Yorumlayıcı ile Çalışma
Şimdi, eylemde görmek için Scala Interpreter’a Merhaba Dünya yazalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | scala> "Merhaba Dünya" val res1: String = Merhaba Dünya scala> println("Merhaba Dünya") Merhaba Dünya scala> "Merhaba Dünya".getClass().getName() val res3: String = java.lang.String scala> res1 val res4: String = Merhaba Dünya scala> |
REPL Shell/Tercümana ilettiğimiz çok basit bir komuttu. İki şekilde denedik. İlki, String ile çevrili çift tırnak olarak geçirilen “Hello, World” değişmez dizesiydi. Aynı Hello, World’ü ancak println() yöntemiyle yazdırmak için ikinci komut çağrısı.
Değerlendirilen bir ifade olarak kabul edildi. Bu nedenle yorumlayıcı, sonucu res0 önekiyle birlikte bir tanımlayıcıyla yazdırdı: yani sonuç 0 → sonuç girişlerinin 0. dizini. Sonraki çağrıların (3. ve 4. komutlardan başlayarak) sonucun res1: ve res2: ile yazdırıldığını görebilirsiniz. 3. komut yinelenen aynı komuttu, ancak REPL Yorumlayıcısının her komutu ayrı bir komut olarak değerlendirdiğini ve bir sonraki sonuç bölümü olan res1: ile yazdırdığını göstermek için. 4. komut, komut satırında bazı yöntemleri çağırmaktır. Komut sonucu res2: ile yazdırdı. Benzer şekilde, sonraki ifadeler, artan res indeksi ile birlikte sonuçlarla birlikte yazdırılacaktır.
İlginç olan kısım, sonuç adlarını sonraki işlemler için bir değişken olarak doğrudan kullanabilmenizdir, çünkü Scala Yorumlayıcı, sonuç girişlerini REPL Yorumlayıcı çalıştığı sürece bellekte saklar. Bunu, res1 ve res2’de doğrudan bir değişken gibi kullanıldığı ve yorumlayıcının karşılık gelen değerleri o anda ve orada yazdırdığı son 2 çağrıda eylemde görebilirsiniz.
Yorumlayıcıdan Çıkmak
İşimiz bittiğinde, tercümandan normal bir şekilde çıkmak her zaman iyidir. Bunu yapmak için lütfen :q girerek Yorumlayıcıdan çıkıp normal Komut İstemi / Terminal’e geri dönebilirsiniz.
Scala dosyasında Merhaba Dünya
Daha önce gördüğümüz gibi, REPL yorumlayıcısına girilen komutlar ve ifadeler kısa ömürlüydü ve Yorumlayıcıdan çıktığınızda onları geri alamazsınız. İleride betiklerimizle/kodlarımızla herhangi bir sayıda çalışmamız gerekirse, Kaynak kodunu bir Java programı gibi bir dosyaya kaydetmek daha iyidir.
Bir Java programının .java olarak nasıl kaydedileceği ile ilgili tipik bir durumdur ve .class adlı bir sınıf dosyası almak üzere kaynak kodunu derlemek için javac .java’yı kullanırız ve ikili dosyayı yürütmek için Java yorumlayıcısını kullanırız. java dosyası olarak, Scala dosyası için de aynı parçalara sahibiz.
Kaynak dosya adını .scala olarak kaydederiz ve kaynak kodunu derlemek için scalac .scala’yı ve ikili sınıf dosyasını yürütmek için scala ‘i kullanırız. Bunları aşağıda aynı Merhaba Dünya scala programı için çalışırken göreceğiz.
1 2 3 4 5 6 7 | object Main { def main(args: Array[String]): Unit = { println("Merhaba Dünya!") } } |
Çıktı:
1 2 3 | Merhaba Dünya! |
Yapı daha çok bir Java programına benzer, burada bir argüman olarak bir String dizisini alan (Komut Satırından kabul edilecek) bir main() metodu tanımlıyoruz ve bu, Main adlı iskeletin içine yerleştirilmiş. Lütfen nesnenin Scala’da kolayca Singleton örneği oluşturmamıza yardımcı olan bir anahtar kelime olduğunu unutmayın – bu, bir JVM içindeki bir sınıfın yalnızca bir örneği anlamına gelir.
Scala’da bir metod, def anahtar sözcüğü kullanılarak tanımlanır ve parametre, Veri türü ile birlikte parametre adından sonra iki nokta üst üste işaretiyle, türüyle birlikte bildirilir. Burada gördüğünüz gibi, args adlı parametre Array[String] türündedir. Dönüş türü, burada Scala’nın veri türlerinden biri olan Unit olan yöntem bildiriminin sonunda belirtilir. Yöntem tanımı burada bir = işaretiyle ve küme parantezleri { ve } ile ayrılmıştır.
main metodundaki yürütülebilir tek ifade, println() yöntemini çağırarak sabit “Merhaba, Dünya” Dizesini konsola yazdırmaktı.
Şimdi yukarıdaki scala programını derleyip çalıştıralım. Aşağıda verildiği gibi oldukça yalındır.
1 2 3 4 5 6 | scalac Main.scala C:\Users\HYX> scala Main Merhaba Dünya |
İlk komut, kaynak kodumuzu bir .class dosyasında derlemek için Scala derleyicisi olan scalac‘ı çağırmaktı. Derleme başarılıysa, konsolda herhangi bir metin görüntülenmeden komut istemine geri döner. İkinci komut, derlenmiş sınıf dosyasını yürütmek için Scala Yorumlayıcısı olan scala‘yı çağırmaktı. Programa göre, konsolda Merhaba Dünya görüntülendi.
Scala’da val ile var arasıdaki fark
Scala’daki çok önemli ve önemli anahtar kelimeleri anlayalım. Bunlar val ve var. Tahmin edebileceğiniz gibi, bunlar kaynak kodda/kodda değişkenlerin değerini daha sonraki bir zamanda değiştirme yeteneğini gösteren tanımlayıcılardır.
var, değişkenin değerinin değişken bir yapısını gösterir. Bu, bir değişkenin değeri, ilk bildirimden sonra daha sonra değiştirilebilir.
val, Java’daki bir final anahtar kelime gibi, değişkenin değerinin değişmez bir doğasını gösterir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | scala> var isim ="Hayri" var isim: String = Hayri scala> isim ="Ahmet" // mutated isim scala> val soyisim ="KOÇ" val soyisim: String = KOÇ scala> soyisim ="CAN" ^ error: reassignment to val scala> |
Stringler ile Çalışmak
Scala, bir String’i bir karakter dizisi olarak ele alır. Kendi başına birkaç yöntemi vardır ve String, StringBuilder vb. gibi Java API sınıflarından yöntemleri kullanmamıza izin verir.
Dizeler ve yöntemleri üzerinde Scala REPL yorumlayıcısıyla biraz oynayalım. Aşağıdaki ifadeler (veya kod parçacıkları) kendiliğinden açıklayıcıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | scala> "Merhaba Dünya".getClass.getName val res1: String = java.lang.String scala> val mesaj ="Ahmet" val mesaj: String = Ahmet scala> mesaj.length val res2: Int = 5 scala> "TasarımKodlama".foreach(println) T a s a r ı m K o d l a m a scala> "Hayri".drop(3) val res4: String = ri scala> "Hayri".take(3) val res5: String = Hay scala> "Hayri".take(3).capitalize val res6: String = Hay scala> "Hayri".take(3).toUpperCase val res9: String = HAY scala> "hayri ahmet".capitalize val res10: String = Hayri ahmet scala> |
String brileştirme, String karşılatırma, Null kontorlü vb. gibi bazı String örneklerini görelim,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | scala> val s1 ="Merhaba" val s1: String = Merhaba scala> val s2="Merhaba" val s2: String = Merhaba scala> val s3= "M"+"erhaba" val s3: String = Merhaba scala> s1 == s2 val res11: Boolean = true scala> val s4:String = null val s4: String = null scala> s1 == s4 val res13: Boolean = false scala> s1.toUpperCase == s3.toUpperCase val res14: Boolean = true scala> val s1:String = null sval s1: String = null scala> s1 == s2 val res15: Boolean = false scala> |
Sayılarla Çalışmak
Scala, Java ile aynı sayısal veri türlerine sahiptir. Bunlar Char, Byte, Short, Int, Long, Float, Double, Boolean‘dır ve her bir veri türü için aynı veri aralığı/sınırı vardır. Ayrıca AnyRef, AnyVal, Any vb. gibi kendi veri tiplerine sahiptir. Scala web sitesinde bulunan veri türlerinin listesini görebilirsiniz.
Yukarıda listelenen Veri türü adını taşıyan ilgili sınıflarda birkaç yöntemimiz mevcuttur. Aşağıdaki kod parçacıkları/ifadeleri açıklayıcıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | scala> Int.MinValue res4: Int = -2147483648 scala> Int.MaxValue res5: Int = 2147483647 scala> Byte.MinValue res6: Byte = -128 scala> Short.MinValue res7: Short = -32768 scala> Short.MaxValue res8: Short = 32767 |
Yukarıda gördüğünüz gibi, ilgili veri türü sınıfları, her biri için daha düşük ve daha yüksek sınırlar elde etmek için minValue ve maxValue yöntemlerine sahipti. Scala REPL yorumlayıcısındaki ifadeler değerlendirildi ve sonuçları bilgimiz için yazdırıldı.
Scala REPL yorumlayıcısında sayılar üzerinde bazı matematiksel işlemler yapalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | scala> 1 + 1 res13: Int = 2 scala> "1" + "1" res14: String = 11 scala> "1".toInt + "2".toInt res15: Int = 3 scala> "1".toShort + "1".toShort res16: Int = 2 scala> "1".toByte + "1".toByte res17: Int = 2 scala> "1".toLong + "1".toLong res18: Long = 2 |
Yukarıda gördüğünüz gibi, ilk ifade doğrudan değerlendirildi ve sonuç konsola yazdırıldı. 2’ye eşit olan 1 ve 1 sayılarının toplamıydı. Ancak 2. çağrı farklıydı – burada sayılar String değişmezleri olarak verildi ve bu nedenle String Concatenation, 11 sonucunu üreterek gerçekleşti. Temsil edilen sayıları ayrıştırmamız ve dönüştürmemiz gerekirse bir String olarak, bunun için toInt yöntemini kullanabiliriz. Son birkaç ifadede gördüğünüz toByte, toLong, toShort vb. gibi diğer farklı veri türlerine dönüştürmek için benzer yöntemlerimiz var. Bu toInt() vb. yöntemler, dize değişmez değerini karşılık gelen sayısal forma dönüştürür ve sonucu üretmek için matematiksel işlemi uygular.
String değişmezini sayısal bir forma dönüştürmeye çalışırken hata alabileceğiniz bazı olumsuz senaryoları görelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | scala> "129".toByte java.lang.NumberFormatException: Value out of range. Value:"129" Radix:10 at java.lang.Byte.parseByte(Byte.java:150) at java.lang.Byte.parseByte(Byte.java:174) at scala.collection.immutable.StringLike$class.toByte(StringLike.scala:264) at scala.collection.immutable.StringOps.toByte(StringOps.scala:30) ... 33 elided scala> "foo".toInt java.lang.NumberFormatException: For input string: "foo" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:492) at java.lang.Integer.parseInt(Integer.java:527) at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272) at scala.collection.immutable.StringOps.toInt(StringOps.scala:30) ... 33 elided |
İlk ifade, String Literal 129’u bir Byte’a dönüştürmeye çalışıyordu. Ancak, Bayt değer aralığı yalnızca -128 ile 127 arasında olduğu için başarısız oldu. Dolayısıyla, anlamlı bir açıklama içeren bir hata aldınız (yığın izindeki ilk satıra bakın), bu hatayı anlamamıza ve düzeltici eylemde bulunmamıza yardımcı olur. İkinci ifade, sayısal olmayan bir değerin (gerçek Dize değeri) bir Tamsayıya dönüştürülmeye çalışıldığı ve kesinlikle bir NumberFormatException oluşturacağı açıktı.
toInt, toByte yöntemlerinin StringOps sınıfında mevcut olduğunu ve daha sonra StringLike sınıfının toInt() yöntemine yetkilendirildiğini görebilirsiniz. Bu çağrılar, ilgili Wrapper sınıfları Integer, Byte’ın Java API yöntemi parseInt(), parseByte() ile daha da yığılır.
REPL yorumlayıcısı ile bazı aritmetik işlemleri görelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | scala> var sayac=1 var sayac: Int = 1 scala> sayac++ ^ error: value ++ is not a member of Int scala> sayac+=1 scala> sayac val res2: Int = 2 scala> sayac = sayac + 1 // mutated sayac scala> |
Gördüğünüz gibi, ilk ifade ilk değeri 1 olan var count türünde bir değişken bildirdi. Değeri 1 ile artırmak için Java’da ++ kullanıyoruz. Ancak Scala’da, yerinde += kullandığından biraz farklıdır. 2. ifade, ++ kullanımı nedeniyle başarısız olurken, 3. ifade doğru olur. Ancak ifadenin değerlendirilmesi konsolda herhangi bir sonuç vermedi. 4. ifade, artırma işleminden sonra şimdi 2 olan sayım değerini yazdırdı. 5. ifade, bir değişkenin değerine 1 eklemenin olağan yolunu gösterir. Burada değer açıkça değişkene geri atanır ve bu nedenle sonuç (3) konsolda yazdırılır.
Int sınıfında += adında bir metod olmadığı için yukarıdaki 2. ifadede hata aldık.
Scala’da bir dizi sayı ile çalışmanın ne kadar kolay olduğunu görelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | scala> val r = 1 to 10 val r: scala.collection.immutable.Range.Inclusive = Range 1 to 10 scala> var r = 1 to 10 by 2 var r: scala.collection.immutable.Range = inexact Range 1 to 10 by 2 scala> for(i <- 1 to 5) println(i) 1 2 3 4 5 scala> for(i <- 1 until 5) println(i) 1 2 3 4 |
Yukarıdaki ilk ifade, 1’den 10’a kadar bir sayı aralığına sahip olmak için 1’den 10’a kadar olan yapıyı kullandı. Sonuç, scala.collection.immutable.Range.Inclusive türünde bir Aralık’ın oluşturulduğunu ve r değişkenine atandığını gösterir.
2. ifade, artan 2 değeriyle 1’den 10’a kadar bir sayı aralığı oluşturabileceğimizi gösterir. Bu nedenle, sonuçtaki Aralık 1, 3, 5, 7 ve 9 sayılarına sahiptir.
3. ifade, aralıktaki her bir değeri ayrı bir satırda yazdıran bir kapatma ile, parantez içinde 1’den 5’e kadar kullanılacağını belirten bir aralığa sahip bir for döngüsü kullanır.
4. ifade bir for döngüsü kullanır, ancak maksimum değere kadar olana kadar, yani maksimum sınırdan bir eksiktir. Konsolda yazdırılan sonuç 1’den 4’e ve UNTIL(e kadar)5’e kadar değişir.
Scala’da Kontrol Yapılar
Diğer birçok yüksek seviyeli Programlama dili gibi, Scala da kontrol yapıları için if, if-else, switch, while, for kontrol deyimleri ve döngü deyimlerini destekler. Aşağıda bunlardan birkaçının örneklerini göreceğiz.
if ifadesindeki değer doğru sonucunu üretirse ifadenin içindeki kod yürütülür.
1 2 3 4 5 6 7 8 9 10 11 12 13 | scala> var sayi =10 var sayi: Int = 10 scala> if(sayi%2==0)println("Sayı Çift") Sayı Çift scala> sayi =11 // mutated sayi scala> if(sayi%2!=0)println("sayı tek") sayı tek |
If-else – if ifadesinin içindeki koşul doğru olarak değerlendirilmediğinde alternatif bir durumu ele almak istediğimizde yardımcı olur. Önceki örneğe bakın, koşul doğru olarak değerlendirilmediğinde basılmış başka bir şeyimiz olsaydı iyi olurdu, aksi halde konsolda hiçbir şey döndürmez.
1 2 3 4 5 6 7 | scala> var sayi = 5 var sayi: Int = 5 scala> if(sayi%2==0)println("Çift") else println("Tek") Tek |
for – döngüsü, çalıştırılacak sabit bir sınırlı koleksiyonunuz olduğunda kullanışlıdır. İki şekilde kullanılır – basit for döngüsü ve bir koleksiyon aracılığıyla yineleme için bir değişken foreach döngüsü.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | scala> for(i <- 1 to 10) println(i) 1 2 3 4 5 6 7 8 9 10 scala> "merhaba".foreach(println) m e r h a b a |
Yukarıdaki ifadeler, for, foreach kullanımının basit bir şekilde döndüğünü göstermektedir.
for bir yineleyici koruma ile – Scala’da bir for döngüsünün, daha fazla dikkate alınacak öğenin uygunluğunu vermek için koşullu bir ifadeye sahip olabileceği özel bir durumdur. Çalıştırılan koleksiyondaki her öğe için bir filtre görevi görür.
1 2 3 4 5 6 7 8 | scala> for(i <- 1 to 10 if(i%2==0)) println(i) 2 4 6 8 10 |
Yukarıdaki ifade, YALNIZCA çift sayıları filtrelemek için yineleyici korumalı bir for döngüsü kullandı. Öğe YALNIZCA i%2==0 olan filtreden geçiyorsa yazdırılacaktır.
while – döngüsü, koleksiyonun sınırından emin olmadığınız bir durumda, özellikle yinelemenin ne zaman durdurulacağı konusunda kullanılır.
Scala’da Koleksiyonlar
Scala, List, Set ve Map gibi birkaç farklı Koleksiyon öğesi sunar. Aşağıda bir örnekle liste koleksiyonunu göreceğiz.
Bir Listeyi bir fonksiyon olarak çağırarak ve eleman listesini parantez içinde virgülle ayrılmış değerler olarak geçirerek somutlaştırabiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | scala> val sayilar = List(1,2,3,4,5,6,7,8,9,10) val sayilar: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> sayilar.size val res9: Int = 10 scala> sayilar.foreach(println) 1 2 3 4 5 6 7 8 9 10 scala> for(n <- sayilar if(n%2==0)) println(n) 2 4 6 8 10 |
List nesneleri için Scala API’de bulunan ilginç yöntemlerden birkaçını görelim. head yöntemi size ilk öğeyi verir – 0. dizinde, tail yöntemi 0. dizindeki ilk öğe hariç koleksiyondaki geri kalan öğeleri çağırır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | scala> var isimler = List("Hayri","Ahmet","Hüseyin","Recep","Ufuk") var isimler: List[String] = List(Hayri, Ahmet, Hüseyin, Recep, Ufuk) scala> isimler.tail val res18: List[String] = List(Ahmet, Hüseyin, Recep, Ufuk) scala> isimler.head val res19: String = Hayri scala> isimler(0) val res20: String = Hayri scala> isimler.tail.size val res21: Int = 4 scala> isimler.tail(2) val res22: String = Recep scala> isimler.tail.tail.tail.size val res25: Int = 2 |
Sonuc
Umarız Scala Başlangıç Eğitimi’nden keyif almışsınızdır ve bundan iyi bir tat almışsınızdır. Lütfen Scala API’sinde bulunan farklı yöntemleri keşfederek örnekleri kendi başınıza deneyin. Scala, Java’da daha ayrıntılı olan şeyleri yapmanın daha tutarlı ve basit bir yolunu sunduğundan, özellikle profesyonel bir Java geliştirme geçmişinden geliyorsanız, Scala’nın gücünden gerçekten keyif alırsınız.










Yorum Yap