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 🙂