Dart dili kısa kısa

Dart tek thread üzerinde çalışır.

*sabit tanımlar;
-final: değer atandıktan sonra, bellekte yer ayrılması sadece değere erişildiğinde olur. (classlar/ogrenci classı)Instance değişkenler sadece final olarak tanımlanır. Const ile tanımlama için static const olmalıdır.
-const: derleme anında atanır, kullanılmasa bile bellekte yer kaplar.


*~/: bölme işleminde int kullanılmak isternirse tilda kullanılabilir.
*{}: method parametrelerinde parametrenin opsiyonel olduğunu belirtir. 
*[]: method parametrelerinde parametrenin sırasız adı ile verilmesini sağlar.

*get/set: classlarda methoda get set atamalarında derğer = ile verilir. Ör;
void set ogrnoAta(int no){
	this.ogrNo = no;
}
Kullanımı;
ogr.ogrnoAta=20; //ogr.ogrnoAta(10) method gibi atamada hata alınır get/set için.


*Constructor içerisinde bir tane tanımlama yapılabilir. Parametre alır veya alamaz kurucu şeklinde, çünkü overloading yok. Birden fazla tanımlama için static olarak yapılabilir.
Eğer birden fazla constructor tanımı yapılmak isteniyorsa isim verilir method gibi tanım yapılır.
class Ogrenci{
	int ogrNo;
	
	Ogrenci(){
	}
	
	Ogrenci(this.ogrNo) //ogrNo değerine otomatik atama yapılır.
	{
		
	}
	
	Ogrenci.NumaraAta(int no) //ogrNo değerine isimlendirilmiş cons ile atama yapılır.
	{
		this.ogrNo;
	}
}


*Extend etme şu şekilde;
class Hayvan{	//class Hayvan extends Object{ aslında default class bu şekilde kalıtılır.
	String renk;
	void YemekYe(){
		print("yemek")
	}
}

class Kedi extends Hayvan{
	int yas;
	
	@override
	void YemekYe(){
		print("yemek yeniyor.");
		super.YemekYe(); // kalıtılmış methoddaki kodlarıda çalıştır.
	}
}


*üst sınıf cons çalıştırma, default ust sınıfı extends edilmesine :super() eklenmiş gibi çalışır.
class Hayvan{
	String renk;
	
	Hayvan(){ //const
		print("Hayvan yaratıldı.");
	}
	
	void YemekYe(){
		print("yemek")
	}
}

class Kedi extends Hayvan{
	int yas;
	
	Kedi(String cins){ //const default olarak Kedi():super(){ //önce üst cons çalıştırılır. Üst cons parametre bekliyor ise Kedi(string renk):super(renk){ ile değer gönderilebilir.
		print("Hayvan yaratıldı.");
	}
	
	@override
	void YemekYe(){
		print("yemek yeniyor.");
		super.YemekYe(); // kalıtılmış methoddaki kodlarıda çalıştır.
	}
}


*abstract classlardan instence üretilemez. kalıtılabilir classlar tanımlanır. İçerisinde methodlar ve değişkenler tanımlanır ve method içleri kalıtılan methodda override ile doldurulmak zorundadır.
*abstractlar interface yerinede implements ile kullanılır.
abstract class Sekil{
	int en;
	int boy;
	
	void AlanHesapla();
	void CevreHesapla();
}

class Dikdortgen extends Sekil{
	
}

*extends ile tek bir method yazılır ve çoklu kalıtım olmaz, implements ile kalıtılan bütün methodları her zaman ezmek gerekir.
Interfaceler ortak özellekileri olan fakat kalıtılımsal olark bir ilişki olmayan yapıları bir arada tutmaya yarar.
class Televizyon implements Kumanda,DigerSinif{
	@override
	void SesAc(){
		print("ses verildi");
	}
}

*static tanımlama, static değişkene direk sınıf üzerinden ulaşılır. Static içerisinden, static olmayan diğer değişken ve methodlara ulaşılamaz.;
main()
{
	var cem = Ogrenci();
	Ogrenci.OgrSayisi++;
}

class Ogrenci{
	String ad;
	static const int okulKod = 1246;
	static int OgrSayisi = 0;
}


*lambda function tanımlama;
main()
{
	f1(1,5);
	f2(5,5);
	f3(2,5);
}

function f1 = (int s1, int s2){ //var f1 ilede tanımlama yapılabilir.
	int toplam = s1+s2;
	Print("toplam ", toplam);
}

var f2 = (int s1, int s2){
	return s1+s2;
}

var f3 = (int s1, int s2) => s1+s2;

*higher order functions: bir fonksiyonu parametre olarak alan veya geriye fonskiyon döndüren fonksiyonlardır.
void main(List<String> args) {
  Function sayilariTopla = (s1,s2) => print(s1+s2);
  birMethod("Cem", sayilariTopla);

  var fonk = birDigerMethod();
  print(fonk(3,3));
}

void birMethod(String isim, Function dynamicFonc)
{
  print("Ad $isim");
  dynamicFonc(2,5);
}

Function birDigerMethod(){
  Function sayilarinKaresiniAl = (s1,s2) => s1*s2;
  return sayilarinKaresiniAl;
}


*Lexical Closure: Closure ile bir üst kapsamdaki değişkenlerin değerleri değiştirilebilir.
void main(List<String> args) {
  var isim = "";
  Function IsimGoster = () => {
	isim = "Cem; //fonk dışında tanımlamış değişkene erişebilip değişiklik yapılabildi.
  }
}


*Liste generate;
import 'dart:math';
void main(List<String> args) {

  //List<int> ogrenciNo = List.filled(30, 0);
  //List<int> ogrenciNo = List.generate(30, (index)>= index); function ile doldurulabilir artan şekilde.
  List<int> ogrenciNumaralari = List.generate(30, (index) => rastgeleOgrenciNoOlutur());
  ogrenciNumaralari.forEach((oankiNumara) => print("Ogrenci No $oankiNumara"));

  // List<Ogrenci> tumOgrenciler = ogrenciNumaralari.map((ogrNo){
  //   return Ogrenci("Ogrenci $ogrNo Adı" , ogrNo);
  // }).toList();

  List<Ogrenci> tumOgrenciler = ogrenciNumaralari.map((ogrNo)=> Ogrenci("Ogrenci $ogrNo Adı" , ogrNo)).toList();

  tumOgrenciler.forEach((ogr) => print("Sadece Öğr Adı: ${ogr.ad}"));
  tumOgrenciler.forEach((ogr) => print("Ogrenci Bilgileri override ile: ${ogr}"));
}

int rastgeleOgrenciNoOlutur()
{
  int olusturSayi = Random().nextInt(60);

  if(olusturSayi != 0)
    return olusturSayi;
    else {
      var yeni = rastgeleOgrenciNoOlutur();
      return yeni;
    }
}

class Ogrenci{
  String ad;
  int no;

  Ogrenci(this.ad, this.no);

  @override
  String toString() {
    return "$ad ve $no";
    //return super.toString();
  }
}


*async kullanımı, dart tek threadte çalıştığı için uzun süren işlemleri arkaplanda devam ettirilmesinde kullanılır.
import 'dart:async';
import 'dart:math';

void main(List<String> args) {
  var random = Random();
  var future = new Future.delayed(new Duration(seconds: 3), (){
    if(random.nextBool()){
      return 100;
    } 
    else{
      throw "boom";
    }
  });

  future.then((value) {
    print("Completed $value");
  }, onError: (error){
    print("Error $error");
  });

  var ffuture = Future.value('a').then((sonuc) => print("Sonuç $sonuc"));
  zincirlemeFuture();

}

void zincirlemeFuture(){
  var ffuture = new Future.value('a').then((v1){ //v1 içeriğinde a var
    return new Future.value('$v1 b').then((v2){ //v2 = a b
      return new Future.value('$v2 c').then((v3){ //v3 = a b c 
        return new Future.value('$v3 d'); // v2 = a b c d
      });
    });
  });

  ffuture.then(print, onError: print); //future.then ilk parametre içerisinde abcd var
  ffuture.then((sondeger) => print("son değer $sondeger"), onError: print); //future.then ilk parametre içerisinde abcd var
}

/* //FUTURE
import 'dart:io';
import 'dart:async';

void main(List<String> args) {
  print("start");
  
  dosyaIceriginiGoster();

  print("end");
}

dosyaIceriginiGoster() async{
    print("içerik geliyor");
    
    String dosyaicerigi = await dosyaIndir();
    print("Dosya İçeriği: $dosyaicerigi");

  Future<String> dosyaicerigithen = dosyaIndir();
  dosyaicerigithen.then((sonuc)=> print("Dosya İçeriği then ile: $sonuc"));

  }
  
Future<String> dosyaIndir() {
  print("Dosya indirme başlandı:");
  
  //sleep(Duration(seconds: 5));
  Future<String> sonuc = Future.delayed(Duration(seconds: 3), (){
    return "İndirilen içerik bu";
  });

  print("Dosya indirilme bitti");
  return sonuc;
}*/



import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;

void main(List<String> args) async{
 
  var func1 = (int v) async => v+1;
  var func2 = (int v) async => v-1;
  var func3 = (int v) async => v*10; 

  var value = 10;
  value = await func1(value);
  value = await func2(value);
  value = await func3(value);
  print(value);

  var response = await http.get('http://google.com');
  print(response.body);

  errorWhenCompleted();

}

void errorWhenCompleted(){
 var random = Random();
  var future = new Future.delayed(new Duration(seconds: 3), (){
    if(random.nextBool()){
      return 100;
    } 
    else{
      throw "boom";
    }
  }).timeout(Duration(seconds: 2));

  future.then(print).catchError(print).whenComplete((){
    print("tamamlandı.");
  });

  var f2 = future.catchError(print);
  var f3 = future.whenComplete(()=>print("Sonuç geldi"));

  //var f4 = future;
}