👋

freezedのimmutableの仕組みメモ

2 min read

dartでimmutableなオブジェクトを作成するライブラリとしてfreezedというのがある。インストールとか書き方とか機能とかは公式とか見るとして、どうimmutableになるかのメモ。


abstract class Person with _$Person{
  factory Person({String name,int age}) = _Person;
}

と書くと、builder_runnerはfactoryで引数で渡されたメンバのgetterを定義したmixinの_$Personを作成する(実際にメンバが定義されているのは_$_Personでメンバはもちろんfinalで定義されている)

mixin _$Person {
  String get name;
  int get age;
  $PersonCopyWith<Person> get copyWith;
}

とgetだけ定義されているので、

var person1 = Person(name:'hoge',age:10);
//person1.name = 'fuga'; //memberにはgetしか無いので代入できない

となり代入不可になります。変更したければ、

person1 = person1.copyWith(name:'fuga');

として別オブジェクトを作成します(copyWithも自動生成してくれています)。

freezedで作成したクラスもメンバとして渡せます。


abstract class Glasses with _$Glasses{
  factory Glasses({String brand,int price}) = _Glasses;
}


abstract class Person with _$Person{
  factory Person({String name,int age,Glasses glasses,MutableClass mutableClass}) = _Person;
}
var person1 = Person(name:'hoge',age:10,glasses: Glasses(brand:'メガーネ',price: 10000));

//person1.glasses = Glasses(brand:'鉄のメガーネ',price: 10); //memberにはgetしか無いので代入できない
//person1.glasses.price = 20000; //glassesもimmutableなのでそのメンバのpriceも代入できない

逆に普通にクラスも渡せるので

class MutableClass{
  MutableClass(this.name);
  var name;
  String toString(){
    return 'MutableClass($name)';
  }  
}

var person1 = Person(name:'hoge',age:10,glasses: Glasses(brand:'メガーネ',price: 10000),mutableClass:MutableClass('mutable1'));

var person2 = person1.copyWith(name:'fuga');
//person2.mutableClass = MutableClass('mutable2');//memberにはgetしか無いので代入できない
person2.mutableClass.name = 'mutable2';  //これはできる(MutableClassはimmutableではない)

print(person1.toString());
print(person2.toString());

とmutableClass自体はimmutableではないのでperson1.mutableClass.nameは変更できてしまう。それにより出力結果は

Person(name: hoge, age: 10, glasses: Glasses(brand: メガーネ, price: 10000), mutableClass: MutableClass(mutable2))
Person(name: fuga, age: 10, glasses: Glasses(brand: メガーネ, price: 10000), mutableClass: MutableClass(mutable2))

とperson1.mutableClass.nameの出力結果も'mutable2'となってしまう。全部immutableにしましょう。

Discussion

ログインするとコメントできます