Temelden İleri Seviyeye Dart Programlama

Berkcan Gümüşışık
Yetkin Yayın
Published in
11 min readJul 10, 2022

Merhaba arkadaşlar. Bu yazımda en temelden ileri seviyeye Flutter’ın temeli olan Dart programlama dili hakkında bilgi vererek hızlı bir dart turuna çıkacağız. Kemerleri bağlayın uçuşa geçiyoruz.

Dart Nedir?

Dart programlama dili, Google tarafından geliştirilen, açık kaynak kodlu, nesneye dayalı bir programlama dilidir. C tabanlı bir dil veya Java gibi herhangi bir nesneye yönelik programlama dillini biliyorsanız, sizin için Dart dilini öğrenmek çok daha kolay olacaktır.

Dart Yazmak İçin Kullanılan IDE’ler

Dart kullanmak için herhangi bir text editörü de yeterli olacaktır. Ama gelecekte Flutter öğrenmeyi de istiyorsanız VSCode ya da Android Studio kullanmanızı öneririm. Eğer bilgisayarım kaldırmaz diyorsanız da Dartpad ya da Replit gibi online kod editörlerini de kullanabilirsiniz.

Bilgisayarınıza Flutter’ı nasıl kuracağınızı bilmiyorsanız aşağıdaki yazımdan rahatlıkla ulaşarak kurabilirsiniz.

Sözü fazla uzatmadan Dart programlama dilini öğrenmeye başlayalım.

1- print() Komutu ve Temel Başlangıç

Kodlarımızı çalıştırmak için bir main metoduna ihtiyaç duyarız main metodu olmadan kodlarımızı çalıştıramayız. Main metodunun yazımı aşağıdaki gibidir.

void main() {}

Programlama dünyasının klasiklerinden olan “Hello World” yazdırmadan olmaz :) Bunu ekrana bastırmak içinse print() fonksiyonunu kullanıyoruz. Kodlarımızın sonuna ; koymayı unutmayalım. Yoksa kodumuz hata verecektir.

void main() {print("Hello World");}

2- Yorum Satırları

Kodumuz çalıştırılırken çalışmayan ve projeyi geliştirirken hem kendimiz için hem ekip arkadaşlarımız için bıraktığımız yorum satırları Dart dilinde aşağıdaki gibi kullanılmaktadır.

// Tekli yorum satırı yazmayı sağlar./* */  birden fazla yorum satırı için kullanılır.

3- Değişkenler

Değişkenler, programlama dilinde işlediğimiz verileri bilgisayarın hafızasında tutmak için yapmış olduğumuz tanımlamalardır.

Değişkenler bizleri kod hamallığından kurtarır. Mesela ekrana 20 tane “Merhaba” yazdırmak istediğimizi düşünelim. Daha sonra da “Merhaba” yerine “Merhaba Berkcan” yazdırmak istiyorum. Bunun için 20 satır değiştirmekse atama yaptığım değeri değiştirmem 20 kod satırını da etkileyecektir.

Değişken tanımlarken veriTürü verininAdi = “Verinin değeri”; şeklinde tanımlanır.

String değerler yazıları tutar ve tırnak içerisinde yazılır. int veri tipinde ise tam sayılar tutulur ve direkt olarak yazılır.

int money= 150; // Tam Sayı Değerleri int anahtar sözcüğüyle ifade edilir.
String hello= "Hello" // Yazı Değerleri String anahtar sözcüğüyle ifade edilir.
print(hello + money); // aynı türden olmayan veriler toplanamaz.

Farklı veri türlerini bir arada kullanmak için $ işareti kullanılır. Yukarıdaki örneği baz alalım. money int veri türü, hello ise string bir veri türüdür. Buradan “$money” yazarsak sorun düzelecektir.

print(hello + " " + "$money");

$ kullanırken toplama yapmak için ${} kullanılmaktadır.

print("Merhaba" + " " + '${25 + 5}');

double veri tipiyle birlikte ondalıklı sayıların değerlerini tutarız.

double sayi = 5.4; // Ondalıklı Sayı Değerleri double anahtar sözcüğüyle ifade edilir.

Tam sayıyı normalde böldüğümüz zaman ondalıklı sayı olması gerekir bu yüzden hata verir. ~ işareti kullanarak / yaparsak int sonucu çıkarır.

userMoney = userMoney ~/ 2;

Veri türünün tipini vermeden var anahtar kelimesini kullanarak da değişken tanımlamak mümkündür. var anahtar kelimesiyle birlikte veri türünü kendisi otomatik olarak belirlemektedir. Ama veri tipinin türünü vermek daha sağlıklı bir yöntem olacaktır.

var userName = "Berkcan";

İçerisine bir kere veri atıldığında bir daha değiştiremeyeceğiniz yapılara sabitler denir. final ve const olmak üzere 2 çeşidi vardır.

final int bankMoney = 100;
const int data = 15;

final ve const arasındaki farka baktığımızda final uygulama çalıştığında o an çalışan değeri alır ve değeri atar. Const ile proje başlarken kod compile edildiği anda değiştirilmez.

Doğru veya yanlış değerleri bool ile tutuyoruz.

bool isCustomerRich = true;

4- Koşullu İfadeler

Koşullu ifadeler if else if else ve switch case olmak üzere iki gruba ayrılır.

a. if else ve else if

If else ve else if yapısının kullanımı aşağıdaki gibidir.

if(koşul 1){  // Koşul 1 doğruysa çalışacak kodlar.}else if(koşul 2){  // Koşul 2 doğruysa çalışacak kodlar.}else{  //Koşul 1 ve Koşul 2 doğru değilse çalışacak kodlar.}

If else yapısına örnek olarak bir öğrencinin harf notunu hesaplayarak ekrana yazdıran bir uygulama yapalım.

int notDegeri = 150;if(notDegeri >= 90 && notDegeri<=100){   print("Notunuz : AA");}else if(notDegeri >= 80 && notDegeri < 90 ){   print("Notunuz : BA");}else if(notDegeri >= 70 && notDegeri < 80){   print("Notunuz : BB");}else if(notDegeri >= 60 && notDegeri < 70 ){  print("Notunuz : CB");}else if(notDegeri >= 50 && notDegeri < 60){  print("Notunuz : CC");}else if(notDegeri >= 0 && notDegeri < 50 ){  print("Notunuz çok düşük yazmaya tenezzül bile etmedik");}else{  print("Hatalı veya eksik giriş");}

b. Switch Case

Ard arda if -else if kullanmak yerine genellikle switch yapısı tercih edilir. Her case sonuna break konularak tüm kodu taramadan ilgili case bloğuna gelince kodu çalıştırıp durması sağlanır.

final int classDegree = 2;switch (classDegree) {   case 0:     print("Yeterli");     break;   case 1:     print("Olur");     break;   case 2:     print("Bravo");     break;   default:     print("Başarısız");}

5. Operatörler

Koşullu ifadeleri kullanırken karşılaştırma operatörlerine ve mantıksal operatörleri oldukça fazla kullanmaktayız.

Karşılaştırma Operatörleri

== eşittir!= eşit değildir> büyüktür< küçüktür>= büyük eşittir<= küçük eşittir

Mantıksal Operatörler

&& AND => Her iki koşulun sağlanması durumunda true olur.|| OR => İki koşuldan biri doğruysa true olur.! NOT => var olan durumu tersine dönüştürür.

Aritmetik Operatörler

int money = 15;
money += 1; //money = money + 1
money++ // money = money + 1
+ Toplama
- Çıkarma
/ Bölme
* Çarpma
% Mod alma

6- Döngüler

Döngüler belirli kodları tekrar çalıştırmak amaçlı yapıdadır.

a. For Döngüsü

Sınırı belli olan döngü çeşididir.

for(var baslangic;bitişŞartı; artış){     //Tekrarlanacak kod yapısı}

For döngüsü ile 0 ile 4 arasındaki sayıları ekrana bastırmak istersek yazacağımız kod aşağıdaki gibidir.

for (var i = 0; i < 5; i++) {      print(i);}

For döngüsünün bir diğer özelliği de dizi elemanları tek tek dolaşmasını sağlayan diğer dillerde kullanılan Foreach döngüsüne benzer Döngünün yapısı aşağıdaki gibidir:

for(var veri in veriKümesi){     //Tekrarlanacak kod yapısı}

Elimizde bir isim listesi olduğunu var sayalım. Bu listeyi adım adım dönecek kod yapısı aşağıdaki gibidir.

List isimListesi = ["Berkcan", "Şevval", "Nurana", "Mete"];for (var isim in isimListesi) {     print(isim);}

b. While Döngüsü

Döngünün sonu belirsizdir ve eğer bir sayaç kullanmazsak sonsuz döngüye girerek bilgisayarı zora sokabilir.

while(şart){    //Tekrarlanacak ifade}  

Bir while döngüsü örneği aşağıdaki gibi verilebilir.

var sayac = 1;while (sayac < 4) {    print(sayac);    sayac += 1;}

c. Do While Döngüsü

While döngüsüne girmeden önce kod doğru olsun ya da olmasın en az bir kere ekrana çıktı verir. Yapısı aşağıdaki gibidir:

do{   //Tekrarlanacak kod bloğu}while(koşul);

Break ve Continue Deyimi

Break çalıştığı zaman o döngünün tamamen durmasını sağlar. Continue çalıştığında ise yalnızca o değeri atlayarak döngünün çalışmasına devam eder.

7- Listeler

Aynı veri türündeki elemanları bir arada tutmayı sağlar. Listelerde indeks numarası 0'dan başlar. Liste tanımlanırken List<veri türü> listeAdi = [elemanlar]; şeklinde tanımlanır.

List<int> moneys = [100, 110, 500];print("1. Müşterinin parası : ${moneys[0]}");

Liste Metotları

Aşağıdaki metodlar dışında daha birçok metot vardır. Ama yazının fazla uzamaması adına birkaç tanesini yazıma ekleyeceğim.

a. sort() Metodu

sort() metoduyla birlikte liste elemanlarını sıralama işlemi gerçekleştirir. Elimizde [100, 110, 500, 200, 300] böyle bir liste olduğunu var sayalım ve metodu çalıştırınca çıktının [100, 110, 200, 300, 500] şeklinde sıralar. Metinsel ifadelerdeyse alfabetik sıralama yapar.

List<int> moneys = [100, 110, 500, 200, 300];moneys.sort();print(moneys);

b. add() Metodu

Listenin sonuna yeni eleman eklemeyi sağlar. Listenin başında final eklense bile eleman eklemede bir sorun olmayacaktır.

List<int> moneys = [100, 110, 500, 200, 300];moneys.add(500);print(moneys);

c. insert(index, eleman) Metodu

Listenin istenen bir indeksine yeni eleman eklemeyi sağlar.

List<int> moneys = [100, 110, 500, 200, 300];moneys.insert(2,300);print(moneys);

c. clear() Metodu

Listenin içini tamamen boşaltır.

List<int> moneys = [100, 110, 500, 200, 300];moneys.clear();print(moneys);

d. remove() Metodu

Listeden belli elemanı silmeyi sağlar.

List<int> moneys = [100, 110, 500, 200, 300];moneys.remove(110);print(moneys);

e. removeAt() Metodu

Listeden belli indexteki elemanı silmeyi sağlar.

List<int> moneys = [100, 110, 500, 200, 300];moneys.removeAt(110);print(moneys);

e. lenght() Metodu

Listeden eleman sayısını bulmayı sağlar.

List<int> moneys = [100, 110, 500, 200, 300];moneys.lenght();print(moneys);

f. contains() Metodu

Listede bir elemanın var mı yok mu olduğuna bakar, varsa true yoksa false değeri döndürür.

g. any() Metodu

Oluşturulan bir durumun herhangi bir eleman tarafından sağlanma durumunu bir boolean değeri döndürerek kontrol etmemizi sağlar.

var sportlist = ['cricket', 'tennis', 'football'];
print(sportsList.any((e) => e.contains(‘cricket’)));

h.where()

Listedeki elemanlardan, oluşturulan durumla uygun eşleşmeyi ekrana getirir.

var ilkListe = [1,2,3,4,5,6];
print(ilkListe.where((i) => i < 4));

Spread Operatörü

Listeleri birleştirmeyi sağlayan operatördür. … ile kullanılır.

var tekSayilar = [1,3,5];var ciftSayilar =[2,4,6];var sonListe= [...tekSayilar,...ciftSayilar];print(sonListe);

8- Fonksiyonlar

Belirli işlemleri temsil eden yapılardır. Kullanma amacımız tekrarlanan kod yapılarının önüne geçmektir. Kodun okunması kolaylaşır. Bir fonksiyon tanımlaması aşağıdaki gibi yapılmaktadır. Fonksiyonlar parametreli de olabilir parametresiz de olabilir.

dönüşTürü fonksiyonAdi(Parametre){   //Kodlar}

Müşteri bizden benim bir müşterim var parası var mı yok mu kontrol eder misin? diye bir soru yöneltiyor ve bunun için nasıl bir fonksiyon yazacağımızı aşağıdaki kodda inceleyelim:

void main() {   final int userMoney = 0;   controlUserMoney(userMoney, 0);}void controlUserMoney(int money, int minValue) {if (money > minValue) {   print("Para var");} else {   print("Para yok");  }}

Eğer fonksiyon içerisinde print yerine return ifadesi kullanırsak fonksiyonu çalıştır ama ben istersem değeri ekrana bastırırım demektir.

Eğer süslü parantez {} kullanırsak burda da parametreler isteğe bağlıdır ama bu parametreleri belirtirken sıralama önemini kaybeder ve de parametreleri geçerken isimlerini vermek zorunda kalırız.

void main(){
final newResult = convertToStandartDolar(100, dolarIndex: 13);
final newResult2 = convertToStandartDolar(100); final newResult3 = convertToEuro(userMoney: 500);}int convertToStandartDolar(int userMoney, {int dolarIndex: 14}) { return userMoney ~/ dolarIndex;}int convertToEuro({required int userMoney, int dolarIndex = 14}) { return userMoney ~/ dolarIndex;}

9- Map

Sırasız bir şekilde elemanları key — value şeklinde saklar. Herhangi bir veri türü saklanabilir ama önemli olan nokta key değerinin eşsiz(tekil) olması gerekir. Sabit uzunlukta değildir. Yapı olarak sözlüğe benzer. Map<keyVeriTürü, valueVeriTürü> değişken = {}; şeklinde tanımlanır. Aşağıdaki örnekte users adında bir map oluşturduk ve daha sonra Ahmet’in parasını ekrana bastırdık.

Map<String, int> users = {"Ahmet": 20,"Mehmet": 30,};print("Ahmet'in parası ${users['Ahmet']}");

Bir banka olsun. Bu bankada müşterilerimin birden fazla hesabı olabilir. 3 müşterimiz olsun. Ahmet Bey’in 3 hesabı vardır. Sırasıyla 100,300,200. Mehmet Bey’in 2 hesabı vardır ve sırasıyla : 30, 50'dir. Veli Bey’in ise 1 hesabı vardır: 30. Bu hesapları kontrol et ve herhangi bir hesapta 150 liradan fazla varsa krediniz hazır deyin.

Map<String, List<int>> bgBank = {"Ahmet": [100, 200, 300]};bgBank["Mehmet"] = [30, 50];bgBank["Veli"] = [30];for (var item in bgBank.keys) {   // Bankanın tüm elemanlarıfor (var money in bgBank[item]!) {  //bgBank[item]!-> musterinin hesaplari demek     //User hesapları dolaşılır.      if (money > 150) {         print("Krediniz hazır");      }    }}

Dart’ın temel yapı taşlarını tamamladıktan sonra şimdi Nesneye Yönelik Programlama kısmına geçebiliriz.

Nesneye Yönelik Programlama

1- Sınıf Yapısı

Sınıf(Class) : Kendi veri türlerimiz veya soyut olan taslaklara denir. Kendi içinde değişkenlere ve methodlara sahiptir.

Nesne : Olusturulan soyut ve taslak olan sınıflardan üretilen örneklere denir.

Sınıf eğer bir uzaktan kumandalı araba ise nesne onu kontrol ettiğimiz kumandadır.

Bir sınıf tanımlamak istersek aşağıdaki bir sınıf tanımlaması yapılır. Class tanımlaması yaparken class SinifAdi{} şeklinde tanımlanır. this anahtar kelimesi bir sınıfın içerisinde, o sınıfın o anki objesine işaret eder. late anahtar kelimesi ise boş bir değişken oluşturup daha sonra atama yapacağını söyler.

void main(){User user1 = User('Berkcan', 15, age: 23, city: 'Ankara');
print(user1.name);
}
class
User {
// Özellikleri yazılmalı// late boş olabileceğini söylememizi sağlıyor late final String name; late int money; late final int? age; late final String? city; User(String name, int money, {required int? age, String? city}) { this.name = name; this.money = money; this.age = age; this.city = city; }}

2- Kalıtım(Inheritance)

Birden çok sınıfta aynı işlemi yapmak istiyorsak bir abstract class yani soyut bir sınıf oluşturarak bu sınıf içerisine ortak özellikler eklenir. Daha sonra extends ile birlikte diğer ekstra özellikler eklenecek sınıflara dahil edilir. super anahtar sözcüğü, hemen üst sınıf nesnesine başvurmak için kullanılan bir başvuru değişkenidir.

void main() {   final userNormal = User("Berkcan", 15);   userNormal.sayMoneyWithCompanyName();}abstract class IUser {  final String name;  final int money;  IUser(this.name, this.money);  void sayMoneyWithCompanyName() {      print("$name $money TL paranız bulunmaktadır");   }}class User extends IUser {   final String name;   final int money;   User(this.name, this.money) : super(name, money);}class BankUser extends IUser {   final int bankingCode;   BankUser(String name, int money, this.bankingCode) : super(name, money);}

3-PolyMorphism(Çok Biçimlilik)

Bir sınıf tek bir sınıfı dahil edebilirken , bir sınıf birden fazla intarface alabilmektedir. Implements ile dahil edilirler. Ortak özelliği olan ancak kalıtımsal olarak alakası olmayan sınıflar bir çatı altında toplanır. Hazır bir sınıf olarak düşünülebilir. @override sadece fonksiyonun bir üst sınıfta da tanımlandığına, ancak mevcut sınıfta başka bir şey yapmak için yeniden tanımlandığına işaret ediyor.

void main() {  var kus = Kus();   kus.fly();}abstract class Hayvan {}abstract class Ucabilenler {   void fly();}abstract class Havlayabilenler {  void bark();}abstract class Kosabilenler {    void run();}class Kopek extends Hayvan implements Havlayabilenler, Kosabilenler {  @override  void bark() {  print("Köpek Havlayabilir");}@overridevoid run() {   print("Köpek koşabilir");  }}class Kus extends Hayvan implements Ucabilenler {
@override
void fly() {
print("Kuş uçabilir.");
}
}
class Insan implements Kosabilenler { @override void run() { print("İnsan Koşabilir."); }}

4- Enum

Enum sınıflandırma işlemini sağlar. Enumlar geliştirme yaparken performansı yüksek performans sağlar.

void main() {  final customerMouse = Mouses.a4;  print(customerMouse.index);  print(customerMouse.name);  if (customerMouse == Mouses.a4) {}  if (customerMouse.name == 'a4') {}}enum Mouses { magic, apple, logitech, a4 }

5- Extension Kullanımı

void main(){
String? name;
if ('ali'.isAdmin()) { print('object'); } name.isAdmin();}extension StringUserCheckExtension on String? { bool isAdmin() { return (this ?? '').toLowerCase() == 'admin'.toLowerCase(); }}

6- Mixin Yapısı

mixinler sınıflarımıza extra özellikler ekleyebileceğimiz, içerisinde fonksiyonlar ve değerler tutabilen, birden fazla mixin ile bir araya getirilebilecek yapılardır. with ile dahil edilir.

class Bank with BankMixin {    @override    void sayBankHello() {        calculateMoney(100);    }}mixin BankMixin {   void sayBankHello();  void calculateMoney(int money) {     print('money');   }}

7- Static Metod ve Değişkenler

Bir değişkenin ya da metodun, bulunduğu sınıftan nesne oluşturmaya gerek kalmadan erişmesi sağlar. Aslında çok faydalı gözüksede bu değişken ve metotlara isteyen herkes erişebilir. Bundan dolayı da çok farklı manipülasyonlar olabilir.

void main(List<String> args) {    print(Asinifi.degisken);    Asinifi.degisken = 100;    print(Asinifi.degisken);   print(Asinifi.oran);   Asinifi.metod();}class Asinifi {   static int degisken = 10;   static final double oran = 10.45;   static void metod() {   print("Merhaba");  }}

8- Hata Yönetimi

Hata yönetimi yaparken karşımıza üç blok çıkar. Try bloğuna hata oluşabilecek kod eklenir. Eğer hata çıkarsa catch yapısına geçer. Finally bloğu ise kod bloğunda ister hata olsun ister olmasın çalışır. Aşağıdaki kod bloğunda sayıyı 0'a böleceğimiz için hata oluşacağından hata bloğuna giderek çalışır.

void main() {   print("Program Başladı");   try {     int sayi = 100 ~/ 0;     print(sayi);   } on IntegerDivisionByZeroException {     print("Bölen 0 olamaz");   } catch (e) {    print("Hata: $e");   } finally {   print("Program bitti");   }}

Kendi hata bloğumuzu oluşturma örneği aşağıdaki gibidir:

void main(List<String> args) {   String userName = "a";   if (userName.length > 2) {       print('a');    } else {       throw UserNameException();     }}class UserNameException implements Exception {    @override    String toString() {       return 'user name null girmişsin bunu düzelt';    }}

9- Future, async ve await İşlemleri

Future : Fonksiyon tanımlanmasında fonksiyon isminden önce gelir. Metodun asenkron çalışacağını ve await metoduyla karşılaşınca çalışmasını askıya alır.

async: Birden fazla işlem yaptırmayı sağlar.

await: İşlem yaparken bazı kodlar hata oluşturur. Hata oluşmaması için await kullanılır.

Future<void> main(List<String> args) async {   print("a");   // 2 saniye bekle sonra gel hiçbir müşteri alma.    await Future.delayed(Duration(seconds: 2));    print("ab");}//Bir servise cevap sonradan gelecek ve ben bu işlem yapılana kadar devam etmek istiyorsam kullanırız.

Kısa Bir Kapanış

Bu yazımızda Dart programlama dilinin temellerini ve nesne yönelimli programlama konusuna detaylıca inceledik. Geniş Türkçe bir doküman hazırlama gereksinimi duydum. Çünkü Flutter’ı ezbere öğrenmemek açısından Dart programlama dilinin temellerini öğrenerek Flutter’da yapıların temellerini öğrenmek kolaylaşacaktır. Daha detaylı örnekler ve projeler incelemek isterseniz aşağıdaki Github reposunu inceleyebilirsiniz.

Sorularınız olursa bana istediğiniz zaman ulaşabilirsiniz. Sağlıklı ve bugsuz günler dilerim.

--

--