Fonksiyonlar (Functions)

Dart, gerçek bir nesne yönelimli dil olduğu için fonksiyonlar bile nesnelerdir ve bir tipe sahiptirler. Bu, fonksiyonların değişkenlere atanabileceği veya başka fonksiyonlara argüman olarak geçirilebileceği anlamına gelir. Ayrıca, bir Dart sınıfının bir örneğini bir fonksiyon gibi çağırabilirsiniz. Detaylar için Çağrılabilir nesneleri inceleyin.

İşte bir fonksiyonu uygulamanın bir örneği:

bool gezegenMi(String gezegen) {
    return _gezegenler[gezegen] !== null;
}

Dart fonksiyonlar için tür açıklamalarını önerse de, fonksiyon türü dahi atlamışsanız çalışır:

gezegenMi(String gezegen) {
    return _gezegenler[gezegen] !== null;
}

Sadece bir ifade içeren fonksiyonlar için arrow fonksiyon kullanabilirsiniz:

bool gezegenMi(String gezegen) => return _gezegenler[gezegen] !== null;

=> expr sözdizimi, { return expr; } için bir kısaltmadır. => arrow fonksiyon olarak da adlandırılır.

Not: Arrow (=>) ve noktalı virgül (;) arasında sadece bir ifade —bir deyim— yer alabilir. Örneğin bir if deyimini oraya koyamazsınız, ancak bir koşullu ifade kullanabilirsiniz.

Parametreler

Bir fonksiyonun herhangi bir sayıda zorunlu parametresi olabilir. Bu, adlandırılmış parametreler veya isteğe bağlı pozisyonel parametrelerle takip edilebilir (ancak ikisi birden değil).

Adlandırılmış Parametreler

Adlandırılmış parametreler, açıkça zorunlu olarak işaretlenmediği sürece isteğe bağlıdır.

Bir fonksiyon tanımlarken, adlandırılmış parametreleri belirtmek için {param1, param2, ...} kullanın. Varsayılan bir değer sağlamaz veya adlandırılmış bir parametreyi zorunlu olarak işaretlememişseniz, türleri nullable olmalıdır, çünkü varsayılan değerleri null olacaktır:

/// [kalın] ve [gizli] bayraklarını ayarlar ...
void bayraklariEtkinlestir({bool? kalin, bool? gizli}) {...}

Fonksiyonu çağırırken, paramName: value kullanarak adlandırılmış argümanları belirtebilirsiniz. Örneğin:

bayraklariEtkinlestir(kalin: true, gizli: false);

Bir adlandırılmış parametre için varsayılan bir değer belirtmek için = kullanın. Belirtilen değer derleme zamanında bir sabit olmalıdır:

/// [kalin] ve [gizli] bayraklarını ayarlar ...
void bayraklariEtkinlestir({bool kalin = false, bool gizli = false}) {...}

// kalin true olacak; gizli false olacak.
bayraklariEtkinlestir(kalin: true);

Eğer adlandırılmış bir parametrenin zorunlu olmasını istiyorsanız, parametreleri required ile işaretleyebilirsiniz:

const KaydirmaCubugu({super.key, required Widget child});

Eğer birisi child argümanını belirtmeden bir KaydirmaCubugu oluşturmaya çalışırsa, analizör bir hatayı rapor eder.

Not: Zorunlu olarak işaretlenmiş bir parametre hâlâ nullable olabilir:

const KaydirmaCubugu({super.key, required Widget? child});

Pozisyonel argümanları önce koymak isteyebilirsiniz, Dart buna zorlama yapmaz.

tekrar(kez: 2, () {
  ...
});

İsteğe Bağlı Pozisyonel Parametreler

Fonksiyon parametrelerini [] içine almak, onları isteğe bağlı pozisyonel parametre olarak işaretler. Varsayılan bir değer sağlamazsanız, türleri nullable olmalıdır, çünkü varsayılan değerleri null olacaktır:

String soyle(String kimden, String mesaj, [String? cihaz]) {
  var sonuc = '$kimden diyor ki $mesaj';
  if (cihaz != null) {
    sonuc = '$sonuc bir $cihaz ile gönderildi.';
  }
  return sonuc;
}

İsteğe bağlı parametre olmadan bu fonksiyonu çağırmak için örnek:

assert(soyle('Bayram', 'Merhaba') == 'Bayram diyor ki Merhaba');

Ve üçüncü parametre ile bu fonksiyonu çağırmak için örnek:

assert(soyle('Bayram', 'Merhaba', 'Android') ==
    'Bayram diyor ki Merhaba bir Android ile gönderildi.');

İsteğe bağlı pozisyonel bir parametre için varsayılan bir değer belirtmek için = kullanın. Belirtilen değer derleme zamanında bir sabit olmalıdır:

String soyle(String kimden, String mesaj, [String cihaz = 'telefon']) {
  var sonuc = '$kimden diyor ki $mesaj bir $cihaz ile gönderildi.';
  return sonuc;
}

assert(soyle('Bayram', 'Merhaba') == 'Bayram diyor ki Merhaba bir telefon ile gönderildi.');

main() Fonksiyonu

Her uygulamanın, uygulamanın giriş noktası olarak hizmet eden bir main() fonksiyonu olmalıdır. main() fonksiyonu void döndürür ve opsiyonel olarak bir List<String> parametresi alır.

İşte basit bir main() fonksiyonu:

void main() {
  print('Merhaba, Dünya!');
}

İşte argümanları alan bir komut satırı uygulaması için main() fonksiyonunun bir örneği:

// Uygulamayı şu şekilde çalıştırın: dart run argumanlar.dart 1 test
void main(List<String> argumanlar) {
  print(argumanlar);

  assert(argumanlar.length == 2);
  assert(int.parse(argumanlar[0]) == 1);
  assert(argumanlar[1] == 'test');
}

Komut satırı argümanlarını tanımlamak ve çözmek için args kütüphanesini kullanabilirsiniz.

Birinci Sınıf Fonksiyonlar

Bir fonksiyonu başka bir fonksiyona parametre olarak iletebilirsiniz. Örneğin:

void elemaniYazdir(int eleman) {
  print(eleman);
}

var liste = [1, 2, 3];

liste.forEach(elemaniYazdir);

Bir fonksiyonu bir değişkene atayabilirsiniz, örneğin:

var yuksekSes = (mesaj) => '!!! ${mesaj.toUpperCase()} !!!';
assert(yuksekSes('merhaba') == '!!! MERHABA !!!');

Bu örnek anonim bir fonksiyon kullanmaktadır. Daha fazlasını bir sonraki bölümde bulabilirsiniz.

Anonim Fonksiyonlar

Çoğu fonksiyon adlıdır, örneğin main() veya elemaniYazdir(). Bu fonksiyonu bir değişkene atayarak, bir koleksiyondan ekleyerek veya bir fonksiyonu çağırırken argüman olarak kullanarak bir koleksiyondan ekleyebilir veya kaldırabilirsiniz.

Anonim bir fonksiyon, parantez içinde sıfır veya daha fazla parametre, virgülle ayrılmış, opsiyonel tür açıklamaları ve parantez içinde fonksiyonun gövdesi olan bir kod bloğuna sahiptir:

([Type param1[, …]]) {
  kodBlogu;
};

Aşağıdaki örnek, bir listedeki her öğe için çağrılan map fonksiyonuna geçirilen bir anonim fonksiyonu tanımlar. Liste üzerinde çağrılan fonksiyon, her dizeyi büyük harfe çevirir ve ardından forEach'e geçirilen başka bir anonim fonksiyon tarafından her bir dize ve uzunluğu yazdırılır:

const liste = ['elma', 'muz', 'portakal'];
liste.map((eleman) {
  return eleman.toUpperCase();
}).forEach((eleman) {
  print('$eleman: ${eleman.length}');
});

Eğer fonksiyon sadece bir ifade veya return ifadesi içeriyorsa, arrow fonksiyon kullanarak bunu kısaltabilirsiniz.

liste
    .map((eleman) => eleman.toUpperCase())
    .forEach((eleman) => print('$eleman: ${eleman.length}'));

Leksik Kapsam

Dart, leksik olarak kapsamlı bir dildir, bu da değişkenlerin kapsamının kodun düzenine bağlı olarak statik olarak belirlendiği anlamına gelir.

İşte her kapsam düzeyinde değişkenlerle iç içe geçmiş fonksiyonlar içeren bir örnek:

bool ustDuzey = true;

void main() {
  var mainIc = true;

  void benimFonksiyonum() {
    var fonksiyonIc = true;

    void icIceFonksiyon() {
      var fonksiyonIcIce = true;

      assert(ustDuzey);
      assert(mainIc);
      assert(fonksiyonIc);
      assert(fonksiyonIcIce);
    }
  }
}

Dikkat edin ki icIceFonksiyon(), en üst düzeyden en alt düzeye kadar her düzeyden değişkenleri kullanabilir.

Leksikal Kapanışlar

Bir kapanış (closure), kendi leksikal kapsamındaki değişkenlere erişimi olan bir fonksiyon nesnesidir, fonksiyon orijinal kapsamından çıkarıldığında bile. Aşağıdaki örnekte, makeAdder() fonksiyonu addBy değişkenine erişir ve döndürülen fonksiyon, addBy'yi hatırlar:

/// [miktar] değerini fonksiyonun argümanına ekleyen bir fonksiyon döndürür.
Function ekleyiciOlustur(int miktar) {
  return (int i) => miktar + i;
}

void main() {
  // 2 ekleyen bir fonksiyon oluşturun.
  var ekle2 = ekleyiciOlustur(2);

  // 4 ekleyen bir fonksiyon oluşturun.
  var ekle4 = ekleyiciOlustur(4);

  assert(ekle2(3) == 5);
  assert(ekle4(3) == 7);
}

Fonksiyonların Eşitliğini Test Etme

İşte en üst seviye fonksiyonları, statik yöntemleri ve örnek yöntemleri eşitlik için test etme örneği:

void foo() {} // Bir üst seviye fonksiyon

class A {
  static void bar() {} // Bir statik yöntem
  void baz() {} // Bir örnek yöntemi
}

void main() {
  Function x;

  // Üst seviye fonksiyonları karşılaştırma.
  x = foo;
  assert(foo == x);

  // Statik yöntemleri karşılaştırma.
  x = A.bar;
  assert(A.bar == x);

  // Örnek yöntemleri karşılaştırma.
  var v = A(); // A'nın 1. örneği
  var w = A(); // A'nın 2. örneği
  var y = w;
  x = w.baz;

  // Bu kapanışlar aynı örneği (#2) referans aldığı için
  // bunlar eşittir.
  assert(y.baz == x);

  // Bu kapanışlar farklı örnekleri referans aldığı için
  // bunlar eşit değildir.
  assert(v.baz != w.baz);
}

Return (Dönüş) Değerleri

Tüm fonksiyonlar bir değer döndürür. Eğer belirli bir dönüş değeri belirtilmemişse, return null ifadesi otomatik olarak fonksiyon gövdesine eklenir.

foo() {}

assert(foo() == null);

Bir fonksiyonda birden çok değer döndürmek için, değerleri bir kayıt içinde toplayabilirsiniz.

(String, int) foo() {
  return ('bir şey', 42);
}

Generators (Üreteçler)

Bir değer dizisi üretmeye ihtiyaç duyduğunuzda, bir üreteç fonksiyonu kullanmayı düşünebilirsiniz. Dart, iki tür üreteç fonksiyonunu destekler:

  • Senkron üreteç: Iterable nesnesi döndürür.

  • Asenkron üreteç: Stream nesnesi döndürür.

Senkron üreteç fonksiyonu uygulamak için, fonksiyon gövdesini sync* olarak işaretleyin ve değerleri iletmek için yield ifadelerini kullanın:

Iterable<int> dogalSayilar(int n) sync* {
  int k = 0;
  while (k < n) yield k++;
}

Asenkron üreteç fonksiyonu uygulamak için, fonksiyon gövdesini async* olarak işaretleyin ve değerleri iletmek için yield ifadelerini kullanın:

Stream<int> asenkronDogalSayilar(int n) async* {
  int k = 0;
  while (k < n) yield k++;
}

Eğer üreteciniz özyineliyse (rekürsif), yield* kullanarak performansını artırabilirsiniz:

Iterable<int> dogalSayilariAsagidan(int n) sync* {
  if (n > 0) {
    yield n;
    yield* dogalSayilariAsagidan(n - 1);
  }
}

Harici Fonksiyonlar

Bir harici fonksiyon, gövdesi bildirimi dışında bir yerde uygulanan bir fonksiyondur. Bir fonksiyon bildiriminden önce external kelimesini ekleyin, örneğin:

external void baziFonksiyon(int i);

Bir harici fonksiyonun uygulaması başka bir Dart kütüphanesinden gelebilir veya daha yaygın olarak başka bir dilde yazılmış olabilir. Entegrasyon bağlamında, harici, Dart'ta kullanılabilir hale getirmek için yabancı fonksiyonlar veya değerler için tür bilgisi sağlar.

Harici fonksiyonlar, birinci düzey fonksiyonlar, örnek yöntemler, getter'lar veya setter'lar veya yönlendirici olmayan kurucular olabilir. Eğer değişken final değilse, bir örnek değişkeni de harici olabilir ve bu, bir harici getter ve (değişken final değilse) bir harici setter ile eşdeğerdir.

Last updated