Kurs
Scala hakkında daha fazla bilgi edinmek ister misiniz? DataCamp'in Scala'ya Giriş kursunu alın.
Scala, hem birinci sınıf değerler olarak fonksiyonları hem de yöntemleri içeren bir fonksiyonel programlama dilidir ve aralarında benzerlikler ve farklılıklar bulunur. Hem fonksiyonlar hem de yöntemler, tekrarlanan kodu tek bir yerde tutmak ve belirli bir görevi gerçekleştirmek için çağrılan, yeniden kullanılabilir kod bloklarıdır. Bu sayede kodu hata ayıklamak ve değiştirmek daha kolay olur.
Ancak, fonksiyonlar bir değişkende başlatılan nesnelerdir; yöntemler ise 'def' anahtar sözcüğüyle başlar, ardından yöntem adı, parametre listesi ve dönüş değerini içeren yöntem gövdesi gelir.
Yöntem Bildirimi ve Tanımı
Scala'da yöntem bildirimi ve tanımı için sözdizimi aşağıdadır:
def 'method_name' ('parameters':'return_type_parameters') : ('return_type_of_method') = {
'method_body'
return 'value'
}
Scala'daki bir yöntem aşağıdaki parçalardan oluşur:
- 'def': yöntemleri bildirmek için kullanılan anahtar sözcük.
- 'method_name': yönteminizin adı; lower camel case biçimindedir.
- 'parameters': yöntem parametreleridir; hiç parametre olmayabilir veya yalnızca bir parametre olabilir, birden fazla olduğunda virgülle ayrılır.
- 'return_type_of_parameters': 'parameters_list' veri türüne göre eşleşmelidir ve zorunludur.
- 'return_type_of_method': isteğe bağlıdır; varsayılan olarak 'Unit' döner, ancak 'return' anahtar sözcüğüyle bir değer döndürülebilir.
- Atama Sembolü ('='): isteğe bağlıdır; kullanılırsa dönüş değerini atar, kullanılmazsa yöntem herhangi bir şey döndürmez.
- 'method_body': süslü parantez '{}' içine alınmış kod bloğudur ve gerekli mantığı ya da belirli görev/işlemleri içerir.
- return: gerekli değerleri döndürmek ve programı sonlandırmak için kullanılan anahtar sözcüktür; Scala'da nadiren kullanılır.
Yöntem Çağrısı
Scala'da yöntem çağrısı için sözdizimi aşağıdadır:
method_name(arguments)
Yöntem çağrısı, çağırmak istediğiniz ilgili yöntemin adı olan 'method_name' ile, argümanları da geçerek kolayca yapılır.
Adlandırılmış Argümanlara Sahip Bir Yöntem
Adlandırılmış argümanlara sahip yöntem, yöntem çağrısı sırasında argümanların yöntem parametrelerine geçirilmesine olanak tanır; burada her argüman, yöntem parametreleriyle teker teker eşleştirilir. Aşağıda, işleyen bir yöntem çağrısıyla birlikte Fonksiyon bildirimi ve tanımıyla argümanların geçirilmesine ilişkin bir örnek göreceksiniz:
object calculateResult {
def funSub(x:Int, y:Int) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
println("Difference of the value is: " + funSub(8,6));
println("Difference of the value is " + funSub(y=6,x=8));
}
}
Yukarıdaki program şu çıktıyı verir:
Difference of the value is: 2
Difference of the value is: 2
Yukarıdaki programda 'calculateResult' adlı bir nesne vardır; içinde, hem x hem de y parametrelerinin dönüş türü 'Int' olan ve bütün yöntemin dönüş türü de 'Int' olan 'funSub' adlı bir yöntem bulunur. Bunu, dönüş değerini atayan bir atama ifadesi izler. Süslü parantezler, yöntem gövdesinin başlangıcını gösterir; burada 'diff' değişkeni 0 başlangıç değeriyle başlatılır. Ana yöntem içindeki 'funSub(8,6)' çağrısı 8'i 'x' ile, 6'yı 'y' ile eşleştirir; çıkarma işlemi yapılır, 'diff' değeri döndürülür ve yazdırılır. Benzer şekilde 'funSub(x=8,y=6)' çağrısında da sıralama önemli değildir; parametrelerde 6 'y' ile, 8 'x' ile eşleştirilir, benzer işlem yapılır, değer döndürülür ve sonuç yazdırılır.
Varsayılan Parametre Değerleri
Yöntem parametreleri için ilgili değerleri başlatarak varsayılan değerler belirleyebilir ve argüman geçirmeyerek yöntem çağrısını boş bırakabilirsiniz.
object calculateResult {
def funSub(x:Int=9, y:Int=6) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
print( "The final value is: " + funSub() );
}
}
Yukarıdaki program şu çıktıyı verir:
The final value is: 3
Gördüğünüz gibi, yukarıdaki programda 'calculateResult' adlı bir nesne tanımlıdır ve içinde 'funSub' adlı bir yöntem bulunur; x ve y parametrelerinin dönüş türü 'Int'tir ve tüm yöntemin dönüş türü de 'Int'tir; bunu dönüş değerini atayan bir atama ifadesi izler. Süslü parantezler yöntem gövdesinin başlangıcını gösterir; burada 'diff' değişkeni 0 değeriyle başlatılır. Yöntem çağrısı ana yöntem içinde yapılır; 'funSub()' çağrısı x'i 9'a, y'yi 6'ya başlatır ve işlem gerçekleştirilir; 'diff' değeri döndürülür ve yazdırılır.
Değişken Uzunlukta Argümanlar
Değişken uzunlukta Argümanlar, kullanıcı ya da istemci tarafından herhangi bir sayıda argüman alınabilen argümanlardır. Yöntemdeki son parametre, tekrarlanması gereken '*' kullanılarak bildirilir.
object variableArgument {
def main(args: Array[String]) {
printAll("Scala", "is", "great")
}
def printAll(strings: String*) {
var i : Int = 0;
for( value <- strings ){
println(value);
i = i + 1;
}
}
}
Yukarıdaki program şu çıktıyı verir:
Scala
is
great
Gördüğünüz gibi, yukarıdaki programda 'variableArgument' adlı bir nesne ve 'printAll' yöntemleri vardır; burada değişken uzunlukta 'String*' argümanı sonda tanımlanmıştır ve bir yöntem çağrısı sırasında bir dizi string geçirilebilir. Geçirilen string listesi üzerinde döngü kurulur ve ana fonksiyon içinde çıktı olarak gösterilir.
Özyinelemeli (Recursive) Fonksiyon
Özyineleme, fonksiyonel programlamada kullanılan bir tekniktir; problem, özgün probleme benzer daha küçük alt problemlere tekrar tekrar bölünerek çözülür. Küçük problemler çözülür ve çözümleri birleştirilerek asıl problemin çözümü elde edilir. Bu nedenle böl-ve-yönet ya da azalt-ve-yönet yaklaşımı olarak adlandırılır ve kodun sade ve zarif olmasını sağlar. Özyinelemeli bir fonksiyon yazarken iki noktaya sıkı sıkıya dikkat edilmelidir. Bunlar:
- Temel durum (Base case): Bir fonksiyonda birden fazla temel durum olabilir; bunlar belirlenmezse sonsuz özyinelemeye yol açabilir. Özyineleme olmadan elde edilebilen basit bir çıktı ya da çözüm olmalıdır.
- Özyinelemeli durum (Recursive case): Özyinelemeli fonksiyonun uygulandığı durumdur, yani özyinelemeli çağrıların yapıldığı yer. Problemin özü şudur: Her özyinelemeli çağrıda boyutun küçülmesi gerekir; yani problem, temel duruma ulaşılana kadar daha küçük alt problemlere bölünmelidir. Sonunda çözümleri birleştirerek asıl problemi çözersiniz; bu, böl-ve-yönet yaklaşımıdır.
Verilen herhangi bir sayının faktöriyeli n! olarak gösterilir. Matematiksel olarak şöyle ifade edilir:
Ayrıca, (n-1).(n-2)...3.2.1 ifadesini (n-1)! olarak yazabilirsiniz. Dolayısıyla herhangi bir sayının faktöriyeli her zaman n.(n-1)! şeklindedir.
Şimdi, problemin özyinelemeli olarak çözülüşünü aşağıda görebilirsiniz.
object factorialDemo {
def main(args: Array[String]) {
for (i <- 1 to 5)
println( "Factorial of " + i + ": = " + factorial(i) )
}
def factorial(n: Int): Int = {
if (n <= 1)
return 1
else
return n * factorial(n - 1)
}
}
Yukarıdaki program şu çıktıyı verir:
Factorial of 1: = 1
Factorial of 2: = 2
Factorial of 3: = 6
Factorial of 4: = 24
Factorial of 5: = 120
Yukarıda 'factorialDemo' adlı bir nesne vardır ve içinde, beş kez yineleyen bir döngü içeren bir 'main' fonksiyonu bulunur; ayrıca 'factorial' fonksiyonuna bir fonksiyon çağrısı içerir. Özyinelemeli fonksiyon, beşe kadar n üzerinde özyinelemeli çağrı yapar. n 1'den küçük ya da eşit olduğunda temel durumda durur; sonuç döndürülür ve yazdırılır.
Anonim Fonksiyon
Anonim Fonksiyon, adı olmayan hafif fonksiyon tanımıdır ve Scala'da fonksiyon literal olarak bilinir.
Anonim Fonksiyon için sözdizimi ve örnekler aşağıdadır:
- Anonim fonksiyon için birinci sözdizimi ve örnek:
Sözdizimi:
('first_variable':'data_type', 'second_variable':'data_type') => "certain_expression"
Örnek:
(var1:String:var2:String) => var1 + var2
VEYA
- Anonim fonksiyon için ikinci sözdizimi ve örnek:
Sözdizimi:
(_:'data_type')operator(_'data_type')
Örnek:
(_:String)+(_:String)
İlk sözdizimi, "=>" sonrasındaki ifadenin belirli bir değere değerlendiğini; "=>" öncesindeki değişken listesinin ise ifadeyi değerlendirmek için kullanıldığını gösterir.
Yukarıdaki ikinci sözdizimi bir yer tutucu gibi çalışır; değeri yalnızca bir kez 'joker' karakter olarak kabul eder ve ardından operatör bunların arasında uygulanır.
Aşağıda anonim fonksiyona bir örnek göreceksiniz:
object anonymousDemo
{
def main(args: Array[String])
{
var function1 = (var1:Int, var2:Int) => var1 + var2
var function2 = (_:Int) + (_:Int)
// function call
println(function1(5, 5))
println(function2(7, 3))
}
}
Initializing Scala interpreter ...
Spark Web UI available at http://DESKTOP-03TH7J0:4040
SparkContext available as 'sc' (version = 2.4.3, master = local[*], app id = local-1566986265958)
SparkSession available as 'spark'
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
Yukarıdaki program şu çıktıyı verir:
10
10
Yukarıda, 'anonymousDemo' adlı bir nesne ve içinde iki anonim fonksiyon barındıran bir 'main' fonksiyonu görüyorsunuz. Söz dizimleri farklıdır ancak aynı sonucu üretebilirler; 'function1' çağrıldığında parametreleri doğrudan fonksiyon çağrısından alarak değerlendirilir—5 ve 5 değerleri geçirilir ve sonuç 10 olarak yazdırılır. Benzer şekilde 'function2' de 7 ve 3 geçirilerek çağrılır; değeri bir kez alır ve herhangi bir geçerli 'Integer' kabul eder. Sizin örneğinizde toplama işlemi yapılır ve sonuç çıktı olarak verilir.
Sonuç
Tebrikler, bu eğitimi okumayı tamamladınız.
Scala'da yüksek dereceli fonksiyonlar, iç içe fonksiyonlar, currying fonksiyonlar gibi birçok ileri seviye konu vardır.
Kaynakça:
SCALA TEMELLERİ TURU
Scala | Fonksiyonlar – Temeller
Scala - Fonksiyonlar
Scala'da Anonim Fonksiyonlar
DataCamp'in Scala'ya Giriş kursuna göz atın.
