Dartでオブジェクトの完全な(深い)コピーを作成する言語サポートの方法はありますか?
二次のみ。これを行うには複数の方法がありますか?違いは何ですか?
説明してくれてありがとう!
Dartsの組み込みコレクションは、これを実現するために「from」と呼ばれる名前付きコンストラクターを使用します。この投稿を参照してください:Dartでリスト、マップ、またはセットを複製します
Map mapA = {
'foo': 'bar'
};
Map mapB = new Map.from(mapA);
未解決の問題が示唆しているように思われる限りではありません:
http://code.google.com/p/dart/issues/detail?id=3367
そして具体的には:
.. Objects have identity, and you can only pass around references to them. There is no implicit copying.
パーティーに遅れましたが、私は最近この問題に直面し、次のようなことをしなければなりませんでした:-
class RandomObject {
RandomObject(this.x, this.y);
RandomObject.clone(RandomObject randomObject): this(randomObject.x, randomObject.y);
int x;
int y;
}
次に、次のように、オリジナルでコピーを呼び出すことができます。
final RandomObject original = RandomObject(1, 2);
final RandomObject copy = RandomObject.clone(original);
あまり複雑ではないオブジェクトの場合は、変換ライブラリを使用できます。
import 'dart:convert';
次に、JSONのエンコード/デコード機能を使用します
Map clonedObject = JSON.decode(JSON.encode(object));
クローンを作成するオブジェクトの値としてカスタムクラスを使用している場合、クラスはtoJson()メソッドを実装するか、JSON.encodeメソッドにtoEncodable関数を提供し、デコード呼び出しにreviverメソッドを提供する必要があります。 。
残念ながら、言語サポートはありません。Copyable
私がしたことは、コピーできるようにしたいクラスに実装できるという抽象クラスを作成することです。
abstract class Copyable<T> {
T copy();
T copyWith();
}
次に、これを次のように使用できます。たとえば、Locationオブジェクトの場合です。
class Location implements Copyable<Location> {
Location({
required this.longitude,
required this.latitude,
required this.timestamp,
});
final double longitude;
final double latitude;
final DateTime timestamp;
@override
Location copy() => Location(
longitude: longitude,
latitude: latitude,
timestamp: timestamp,
);
@override
Location copyWith({
double? longitude,
double? latitude,
DateTime? timestamp,
}) =>
Location(
longitude: longitude ?? this.longitude,
latitude: latitude ?? this.latitude,
timestamp: timestamp ?? this.timestamp,
);
}
参照なしでオブジェクトをコピーするには、私が見つけた解決策はここに投稿されたものと似ていましたが、オブジェクトにMAPまたはLISTが含まれている場合は、次のようにする必要があります。
class Item {
int id;
String nome;
String email;
bool logado;
Map mapa;
List lista;
Item({this.id, this.nome, this.email, this.logado, this.mapa, this.lista});
Item copyWith({ int id, String nome, String email, bool logado, Map mapa, List lista }) {
return Item(
id: id ?? this.id,
nome: nome ?? this.nome,
email: email ?? this.email,
logado: logado ?? this.logado,
mapa: mapa ?? Map.from(this.mapa ?? {}),
lista: lista ?? List.from(this.lista ?? []),
);
}
}
Item item1 = Item(
id: 1,
nome: 'João Silva',
email: 'joaosilva@gmail.com',
logado: true,
mapa: {
'chave1': 'valor1',
'chave2': 'valor2',
},
lista: ['1', '2'],
);
// -----------------
// copy and change data
Item item2 = item1.copyWith(
id: 2,
nome: 'Pedro de Nobrega',
lista: ['4', '5', '6', '7', '8']
);
// -----------------
// copy and not change data
Item item3 = item1.copyWith();
// -----------------
// copy and change a specific key of Map or List
Item item4 = item1.copyWith();
item4.mapa['chave2'] = 'valor2New';
ダートパッドの例を見る
あなたがクラスを持っているとしましょう
Class DailyInfo
{
String xxx;
}
クラスオブジェクトdailyInfoの新しいクローンを作成します。
DailyInfo newDailyInfo = new DailyInfo.fromJson(dailyInfo.toJson());
これが機能するには、クラスが実装されている必要があります
factory DailyInfo.fromJson(Map<String, dynamic> json) => _$DailyInfoFromJson(json);
Map<String, dynamic> toJson() => _$DailyInfoToJson(this);
これは、を使用してクラスをシリアル化可能にすることで実行できます。
@JsonSerializable(fieldRename: FieldRename.snake, includeIfNull: false)
Class DailyInfo{
String xxx;
}
JSONで表現できるオブジェクトタイプに対してのみ機能します。
ClassName newObj = ClassName.fromMap(obj.toMap());
また
ClassName newObj = ClassName.fromJson(obj.toJson());
Dartが提供するコピー可能なインターフェースを使用してみてください。
オブジェクトをディープクローンする組み込みの方法はありません。オブジェクトのメソッドを自分で提供する必要があります。
私はJSONからクラスをエンコード/デコードする必要があることが多いので、通常はメソッドを提供MyClass fromMap(Map)
しMap<String, dynamic> toJson()
ます。これらを使用して、最初にオブジェクトをJSONにエンコードし、次にデコードして戻すことで、ディープクローンを作成できます。
ただし、パフォーマンス上の理由から、通常はclone
代わりに別のメソッドを実装します。数分の作業ですが、よく費やされることが多いようです。
以下の例でcloneSlow
は、JSON手法をcloneFast
使用し、明示的に実装されたクローンメソッドを使用しています。プリントアウトは、クローンが実際にはディープクローンであり、への参照の単なるコピーではないことを証明しa
ます。
import 'dart:convert';
class A{
String a;
A(this.a);
factory A.fromMap(Map map){
return A(
map['a']
);
}
Map<String, dynamic> toJson(){
return {
'a': a
};
}
A cloneSlow(){
return A.fromMap(jsonDecode(jsonEncode(this)));
}
A cloneFast(){
return A(
a
);
}
@override
String toString() => 'A(a: $a)';
}
void main() {
A a = A('a');
A b = a.cloneFast();
b.a = 'b';
print('a: $a b: $b');
}
この問題を解決する簡単な方法は、...
たとえば演算子を使用するだけです。たとえば、マップのクローンを作成します。
Map p = {'name' : 'parsa','age' : 27};
Map n = {...p};
また、クラスプロパティに対してこれを行うことができます。私の場合、クラスのリストされたプロパティのクローンを作成する必要がありました。それで:
class P1 {
List<String> names = [some data];
}
/// codes
P1 p = P1();
List<String> clonedList = [...p.names]
// now clonedList is an unreferenced type
//この作品を願っています
void main() {
List newList = [{"top": 179.399, "left": 384.5, "bottom": 362.6, "right": 1534.5}, {"top": 384.4, "left": 656.5, "bottom": 574.6, "right": 1264.5}];
List tempList = cloneMyList(newList);
tempList[0]["top"] = 100;
newList[1]["left"] = 300;
print(newList);
print(tempList);
}
List cloneMyList(List originalList) {
List clonedList = new List();
for(Map data in originalList) {
clonedList.add(Map.from(data));
}
return clonedList;
}
@Phill Wigginsの回答を参照して、.fromコンストラクターと名前付きパラメーターを使用した例を次に示します。
class SomeObject{
String parameter1;
String parameter2;
// Normal Constructor
SomeObject({
this.parameter1,
this.parameter2,
});
// .from Constructor for copying
factory SomeObject.from(SomeObject objectA){
return SomeObject(
parameter1: objectA.parameter1,
parameter2: objectA.parameter2,
);
}
}
次に、コピーする場所でこれを実行します。
SomeObject a = SomeObject(parameter1: "param1", parameter2: "param2");
SomeObject copyOfA = SomeObject.from(a);
ダーツのディープコピーの例。
void main() {
Person person1 = Person(
id: 1001,
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@email.com',
alive: true);
Person person2 = Person(
id: person1.id,
firstName: person1.firstName,
lastName: person1.lastName,
email: person1.email,
alive: person1.alive);
print('Object: person1');
print('id : ${person1.id}');
print('fName : ${person1.firstName}');
print('lName : ${person1.lastName}');
print('email : ${person1.email}');
print('alive : ${person1.alive}');
print('=hashCode=: ${person1.hashCode}');
print('Object: person2');
print('id : ${person2.id}');
print('fName : ${person2.firstName}');
print('lName : ${person2.lastName}');
print('email : ${person2.email}');
print('alive : ${person2.alive}');
print('=hashCode=: ${person2.hashCode}');
}
class Person {
int id;
String firstName;
String lastName;
String email;
bool alive;
Person({this.id, this.firstName, this.lastName, this.email, this.alive});
}
そして、以下の出力。
id : 1001
fName : John
lName : Doe
email : john.doe@email.com
alive : true
=hashCode=: 515186678
Object: person2
id : 1001
fName : John
lName : Doe
email : john.doe@email.com
alive : true
=hashCode=: 686393765
ヘルパークラスを作成します。
class DeepCopy {
static clone(obj) {
var tempObj = {};
for (var key in obj.keys) {
tempObj[key] = obj[key];
}
return tempObj;
}
}
必要なものをコピーします。
List cloneList = [];
if (existList.length > 0) {
for (var element in existList) {
cloneList.add(DeepCopy.clone(element));
}
}
Person
他のオブジェクトのリストである属性を持つオブジェクトをディープコピーするとしますSkills
。慣例により、copyWith
ディープコピーにはオプションのパラメーターを指定したメソッドを使用しますが、任意の名前を付けることができます。
あなたはこのようなことをすることができます
class Skills {
final String name;
Skills({required this.name});
Skills copyWith({
String? name,
}) {
return Skills(
name: name ?? this.name,
);
}
}
class Person {
final List<Skills> skills;
const Person({required this.skills});
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills.map((e) => e.copyWith()).toList());
}
onlyを使用するthis.skills
と、リストの参照のみがコピーされることに注意してください。したがって、元のオブジェクトとコピーされたオブジェクトは同じスキルのリストを指します。
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills);
リストがプリミティブ型の場合は、次のように実行できます。プリミティブ型は自動的にコピーされるため、この短い構文を使用できます。
class Person {
final List<int> names;
const Person({required this.names});
Person copyWith({
List<int>? names,
}) =>
Person(names: names ?? []...addAll(names));
}