🎯Dart Programlama Dili’nde Fonksiyonlar🎯
Hepinize merhabalar. Sizlerle birlikte bu yazımda Dart Programlama Dili’nde fonksiyonları inceleyeceğiz. Ama bu konuyla ilgili tanımlamalar ve açıklamalardan önce gelin, fonksiyon ne demekmiş bir bakalım.
Fonksiyon, matematikte değişken sayıları girdi olarak kabul edip bunlardan bir çıktı sayısı oluşmasını sağlayan kurallardır.
Fonksiyon denildiğinde aklıma gelen gerçek hayat örneğini de açıklamadan olmaz tabii :) .
Resimdeki şekil bir kıyma makinesine benziyor, değil mi? Baktığımız zaman input yani girdi bir parça et ise çıktı olarak yani output kıyma olur. Yani fonksiyon da bu durumda kıyma makinesi diye düşünebilir. Fonksiyon her zaman için girdi alır ve sonuçta bir çıktı döndürür. Bu örnekten yola çıkarak fonksiyonları daha basit düşünebiliriz. Çoğumuzun matematikten hatırlayacağı üzere fonksiyonun formülü f(x)=y şeklinde ifade ediliyor. Burada f(x) kısmındaki x girdi, y ise çıktı olarak isimlendirilir.
Programlamada fonksiyonun en önemli özelliği, içinde barındırdığı ifadeleri tekrardan yazmamıza engel olmasını sağlamaktır. Ufak bir örnekle bunu göstereyim.
Örnekten gözlemleyeceğimiz üzere, “square” isimli fonksiyon, içinde girilen sayının karesini alıyor. Belki bizler direkt fonksiyon içindeki ifadeyi kullanabilirdik ancak ya birden fazla şekilde “square” yazmak istersek nasıl yapacağız? Her seferinde bunu mu yazacaktık? Bu temiz bir kod olmaz ve redundancy yani tekrar oluşur. Bunu engellemek için fonksiyonlar kullanılır.
Fonksiyonların ne olduklarını ve ne amaçla kullanıldığını inceledik. Fonksiyonlar aklınıza gelebilecek her programlama dilinde kullanılırlar. Bu yazımda Dart dilindeki fonksiyonları ele alacağım.
🎯Dart, ilk kez Google tarafından geliştirilen ve daha sonraları ECMA tarafından standart haline getirilen açık kaynaklı ve genel-amaçlı bir programlama dilidir. Dart dili kullanılarak web, sunucu, mobil uygulamalar ve IoT cihazları geliştirilebilir.
Dart da bir nesne tabanlı programlama(Object-Oriented Programming) dilidir. Bu, işlevlerin değişkenlere atanabileceği veya diğer işlevlere bağımsız değişken olarak aktarılabileceği anlamına gelir. Aşağıda fonksiyonun ufak bir gösterimi mevcuttur:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Bool, doğru-yanlış şeklinde çıktı verir. İnt, sayısal bir çıktı verir. Double virgüllü bir sayı çıktısı verir. String yazısal bir çıktı verir. Fonksiyon isminin başına bu türlerden birini yazmasak bile fonksiyon bir çıktı verecektir.
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Fonksiyonları tek satırda kısaca yazmak mümkündür.
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=>
Bu ok işareti { return expr; }
ifadesinin kısa şekilde gösterimidir.
Dart Dili’nde fonksiyonlar aşağıdaki gibi incelenmektedir:
- Optional parameters (İsteğe bağlı parametreler)
- The main() function (Main fonksiyonu)
- Functions as first-class objects (Birinci sınıf nesneler olarak fonksiyonlar)
- Anonymous functions (İsimsiz fonksiyonlar)
- Lexical scope (Değişken etki alanı yapısı)
- Lexical closures (Kapatma)
- Testing functions for equality (Eşitlik durumu kontrolü için fonksiyon test etme)
- Return values (Geriye dönüş değerleri)
Optional Parameters (İsteğe bağlı parametreler), fonksiyonu çağırırken ister o parametre ile çağırırsınız; isterseniz fonksiyonu o parametresiz tanımlanmış gibi çağırırsınız. Zaten isteğe bağlı derken anlatılmak istenen şey de budur.
Fonksiyon çağırırken, parametre ismini özelleştirebilirsiniz. Bunun için kullanım parametreAdı: değer şeklindedir.
enableFlags(bold: true, hidden: false);/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
İsimlendirilmiş parametreler, bir nevi isteğe bağlı parametre olmasına rağmen, kullanıcılar parametre için bir değer sağlaması gerektiğini mutlaka belirtmek zorundadırlar.
const Scrollbar({Key key, @required Widget child})
Eğer biri “child” ifadesi kullanmadan “Scrollbar” oluşturmaya çalışırsa, bu rapora bir sorun olarak bildirilir.
Konumsal parametreler, yazacağımız kodun üzerinde isimlendirilmiş parametrelerin aksine Position değeri sıfır yazması durumunda parametreyi yazmadan doğrudan parametre değerini yazabiliriz. “[]” şeklinde isteğe bağlı konumsal parametre ifade edilir.
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
İsteğe bağlı parametre kullanmadan bir fonksiyon çağrılması aşağıdaki şekilde yapılabilmektedir:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
Fonksiyonun kendi üçüncü parametresiyle çağrılma örneği şu şekilde yapılmaktadır:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
Varsayılan parametre değerleri, fonksiyonumuzda hem isimlendirilmiş hem de konumsal parametreler için varsayılan yani default değerleri tanımlamak için “=” kullanabilir. Varsayılan parametre değerlerinde derleme yani compile aşamasında zamanın sabitleri olmalıdır. Varsayılan parametre değeri sağlanmazsa, varsayılan değer null olur. Bildiğimiz üzere null olma durumu programlamada genel olarak default olarak kabul edilir.
İsimlendirilmiş parametreler için varsayılan parametre değerleri ayarlama örneği şu şekilde yapılmaktadır:
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold will be true; hidden will be false.
enableFlags(bold: true);
Konumsal parametreler için varsayılan parametre değerlerinin nasıl ayarlanacağı aşağıda örnekteki gibidir:
String say(String from, String msg,
[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');
Programlamada kullandığımız list yapıları ve maps yapıları da default yani varsayılan değerlerler olarak kabul edilebilir. Aşağıdaki örnekte tanımlanan “doStuff()” ismindeki fonksiyonda, varsayılan olarak list ve list için parametreler, ayrıca map için varsayılan parametreler ifade edilmektedir.
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
The main() function (Main fonksiyonu), her uygulamada, her kodumuzda giriş görevi gören ve mutlaka olması gereken üst düzey bir işlevdir. Çoğu programlama dilinden main fonksiyonunu çağırdığımızda içine yazdığımız operasyonların gerçekleştiğini görmüşsünüzdür. Main() fonksiyonu void döndürür ve bağımsız değişkenler için isteğe bağlı bir List<String> parametresine sahiptir.
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
Aşağıdaki örnekle ise main() fonksiyonunun bağımsız değişkenler alan bir komut satırı uygulamasını inceleyebiliriz.
// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
Functions as first-class objects (Birinci sınıf nesneler olarak fonksiyonlar) şöyle tanımlanabilir: Bir fonksiyonu başka bir fonksiyona parametre olarak geçirebiliriz:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
Ayrıca değişkene bir işlev de atayabiliriz, aşağıdaki örnekte anonymous fonlsiyon kullanılmıştır:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
Aslında baktığımız zaman main() veya printElement() gibi çoğu fonksiyon adlandırılabilmektedir. Ancak eğer isimlendirmek istemezseniz Anonymous functions (İsimsiz fonksiyonlar), veya closure(kapatma) gibi fonksiyonlar da oluşturabilirsiniz. Bir değişkene isimsiz bir fonksiyon atayabilirsiniz. Böylelikle o fonksiyonu bir koleksiyona ekleyebilir veya koleksiyondan kaldırabilirsiniz.
Anonim yani isimsiz fonksiyonlar aslında baktığımız zaman adlandırılmış bir fonksiyona benzer özellikler göstermektedir. Sıfır veya daha fazla parametre virgülle veya isteğe bağlı açıklamalarla, parantez arası şeklinde ifade edilmektedir:
([[Type] param1[, …]]) {
codeBlock;
};
List yani liste yapısındaki her bir eleman için çağrılan fonksiyon, belirtilen indexteki (bir nevi sıra) değeri içeren bir String ifade göstermektedir.
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
Kodun Outputu,
0: apples 1: bananas 2: oranges
şeklindedir.
Dart Programlama Dili, baktığımız zaman lexically scoped(değişken etki alanı) yani sözcük kapsamına sahip bir dildir. Bu yalnızca kodun düzeni tarafından belirlendiği anlamına gelmektedir. Bir değişkenin scope yani kapsam içinde olup olmadığını “{}” açılış ve kapanışlarına bakarak gözlemleyebilirsiniz.
Aşağıdaki kodda dikkat edilmesi gereken şey “NestedFunction()” fonksiyonunun değişkenleri her seviyeden en üst seviyeye kadar nasıl kullanıldığıdır.
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
Bilgisayar biliminde closure yani kapanış, sözcüksel ortama bağlı serbest değişkenlere sahip first-class yani birinci sınıf bir işlevdir. Lexical closures (Kapatma) , değişkenlere erişimi olan bir fonksiyon nesnesi diyebiliriz. Örnekte “makeAdder()” fonksiyonu “addBy” ismindeki değişkeni tutar. Return edilen yani döndürülen fonksiyon nereye giderse gitsin “addBy” değişkenini remind eder yani hatırlamış olur.
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Testing functions for equality (Eşitlik durumu kontrolü için fonksiyon test etme), için top-level yani üst düzey fonksiyonların; statik yöntemlerin ve instance yani başlangıç yöntemlerinin test edilmesine bir örnek aşağıdaki gibidir:
void foo() {} // A top-level function
class A {
static void bar() {} // A static method
void baz() {} // An instance method
}
void main() {
var x;
// Comparing top-level functions.
x = foo;
assert(foo == x);
// Comparing static methods.
x = A.bar;
assert(A.bar == x);
// Comparing instance methods.
var v = A(); // Instance #1 of A
var w = A(); // Instance #2 of A
var y = w;
x = w.baz;
// These closures refer to the same instance (#2),
// so they're equal.
assert(y.baz == x);
// These closures refer to different instances,
// so they're unequal.
assert(v.baz != w.baz);
}
Tüm bilinen fonksiyonlar bir return yani geriye dönüş değerine sahiptirler. Return values (Geriye dönüş değerleri) tüm fonksiyonlar için geçerli kavramlardır. Eğer bir dönüş değeri yani return değeri belirtilmezse, bir önceki tanımlamalarda belirttiğim gibi ifade null yani default döndürür ve fonksiyon bodysine bir diğer ifadeyle gövdesine doğrudan değil dolaylı olarak eklenir.
foo() {}
assert(foo() == null);
Medium’daki ilk yazım olan bu içerikte sizlere fonksiyon kavramından ve Dart Dili’ndeki kullanımından çeşitli örnekler vererek anlatmaya çalıştım. Umarım beğenmişsinizdir ve sizlere faydalı olabilmişimdir. Sonraki paylaşımlarımda görüşmek üzere .:)