Flutter ‘da Immutability & Equality

yazar:

kategori:

Hadi gelin Dart’ta yani Flutter’da değişmezlik ve eşitliklik nedir? nasıl uygularız gibi sorula birlikte cevap arıyalım.

İlk olarak Droidim adında bir sınıf oluşturalı ve içerisinde name ve age olarak iki parametre tutabileceğimiz ilkel veri tiplerindeki tanımlamaları gerçekleştirelim.

main içerisinde ise Droidim sınıfında x isimli bir instance yani örnek oluşturarak print ile neler döndüğünü anlıyalım.

  class Droidim{
    
    Droidim({required this.name ,required this.age});
    
    String name;
    int age;
    
    @override
   String toString() {
   return 'name:' + name + ' age:' + age.toString();
    }
  }
  

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  print(x.toString());
  x.age = 763;
  print(x.toString());
}

Tahmin edeceğiniz gibi çıktı şu şekilde olacaktır.

name:Selam age:5
name:Selam age:763 

Peki age ve name değişkenlerimizi biz final olarak tanımlasaydık ne olacaktı?

Error compiling to JavaScript:
Warning: Interpreting this as package URI, 'package:dartpad_sample/main.dart'.
lib/main.dart:20:5:
Error: The setter 'age' isn't defined for the class 'Droidim'.
 - 'Droidim' is from 'package:dartpad_sample/main.dart' ('lib/main.dart').
  x.age = 763;
    ^^^
Error: Compilation failed.

Dartpad hatasını yorumladığımızda görüldüğü gibi final olarak tanımladığımız age ve name e bir kez atama yapabiliriz.


 x.age = 763;

İşlemi ikinci bir atama işlemi olduğundan hata almaktadır.Böylece birden fazla atamanın yapılmasını önleyerek kodumuzu sapasağlam bir düzene oturtabiliriz.

Peki ya const?

  class Droidim{
    
    const Droidim({required this.name ,required this.age});
    
    final String name;
    final int age;
    
    @override
   String toString() {
   return 'name:' + name + ' age:' + age.toString();
    }
  }
  

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  print(x.toString());
//   x.age = 763;
//   print(x.toString());
}

Sınıfımızın compile zamanında değişkenlerinin dolu olacağını final ile yaptığımız işaretleme ile belirttik.Bu yüzden değişkenlik olmayacağından const ifadesi hata vermeyecektir.Eğer değişkenlerden birini final yapmazsakkk aman diyim 🙂

https://dart.dev/tools/diagnostic-messages#const_constructor_with_non_final_field

Const tanımlamasını elbette yapamayız.

Peki değişkeni nasıl değişirebiliriz?

  class Droidim{
    
    const Droidim({required this.name ,required this.age});
    
    final String name;
    final int age;
    
    @override
   String toString() {
   return 'name:' + name + ' age:' + age.toString();
    }
  }
  

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  print(x.toString());
  x =  Droidim(name : 'Selam', age : 2 );
  print(x.toString());
}

Tabikii yeni bir örnek oluşturup atama yaparak 🙂

Peki sadece age değişkenini değiştirmek istiyorsak => CopyWith bizim çözümümü olacak.

    Droidim copyWith({
    String? name,
    int? age,
  }) =>
      Droidim(
         
          name: name ?? this.name,
          age: age ?? this.age);
}

copyWith isimli metodumuz ile yeni bir Droidim örneği oluşturulmasını sağladık.Eğer boş bir değişken değeri gönderilirse ( ?? ile sorguladık ) mevcut olanı kullan dedik.

  class Droidim{
    
    const Droidim({required this.name ,required this.age});
    
    final String name;
    final int age;
    
    @override
   String toString() {
   return 'name:' + name + ' age:' + age.toString();
    }
    
    Droidim copyWith({
    String? name,
    int? age,
  }) =>
      Droidim(
         
          name: name ?? this.name,
          age: age ?? this.age);
}
  
  

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  print(x.toString());
  x =  x.copyWith(age: 2);
  print(x.toString());
}

Çıktımız ise

name:Selam age:5
name:Selam age:2 

Son olarakta @immutable işaretini sınıfımıza ekliyerek bunun bir değişmez olduğunuz herkese göstermiş oluruz 🙂

 import 'package:meta/meta.dart';

@immutable
class Droidim{
    
    const Droidim({required this.name ,required this.age});
    
    final String name;
    final int age;
    
    @override
   String toString() {
   return 'name:' + name + ' age:' + age.toString();
    }
    
    Droidim copyWith({
    String? name,
    int? age,
  }) =>
      Droidim(
         
          name: name ?? this.name,
          age: age ?? this.age);
}
  
  

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  print(x.toString());
  x =  x.copyWith(age: 2);
  print(x.toString());
}

Evet değişmezlik ile ilgili umarım aklınızda bir fikir oluşmuştur.Peki ne işe yarayacak ? Henüz uçak yapmadık ama uçakta kullanılan vida hakkında bir fikrimiz oluştu.Devam edelim ve yüksek G kuvvetinde bile temelleri sağlam atılan bu uçağın güvenle uçmasını sağlayalım.

Eşitlik

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  Droidim y = Droidim(name : 'Selam', age : 5 );

  print(x == y );
}

Size çıktı ne olur doğrumu yanlış mı?

çıktımız : false

Tüm değişkenler aynı ve değerleri birbirine eşit neden böyle oldu? Çünkü x ve y deki veri yani Droidim sınıfına ait örnekler arka tarafta farklı bir yerde tutulmakta.Bir otel odasında farklı odalarda duran ikizler gibi düşünebilirsiniz karşılaştırma ise oda numarasına göre yapıldığından hata false dönmekte.

Peki ya çözümü?

  @override
   bool operator ==(Object other) =>
      other is Droidim &&
      other.name == name &&
      other.age == age;

Yukarıdaki kod parçacığı ile eşitlik operatörünün çalışma mantığını ezip yerle bir ettik 🙂 Artık biz nasıl karşılaştırırsak öyle çalışacak.

cevap : true

hashCode

Bir diğer önemli nokta ise hashCode. Eğer == operatörünü eziyorsak hashCode mantığınıda değiştirmeliyiz.

void main() {
  

  Droidim x = Droidim(name : 'Selam', age : 5 );
  Droidim y = Droidim(name : 'Selam', age : 5 );
  print(x.hashCode);
  print(y.hashCode);
  print(x.hashCode == y.hashCode );
}

çıktı

191024135
405255415
false 

Sınıfımızda ezme işlemii gerçekleştirelim

  @override
  int get hashCode => age.hashCode + name.hashCode;

İşte sonuç

209363621
209363621
true 

Evet bu kadar anlatım yeter, bu uzun ve çetrefilli yoldu.Sırada Frezeed ile yukarıdaki tüm işlemleri nasıl yabileceğimizi göreceğiz.Takipte kalın 🙂


Yorumlar

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir