Flutter数据合并插件merger的使用

Flutter数据合并插件merger的使用

merger 是一个用于在 Flutter 中合并 Map<K extends Object, V extends Object?>List<V extends Object?> 的包。它可以处理任意深度的数据合并。

问题解决

merger 可以用来做什么?其主要用途是为我的另一个包 easiest_localization 提供支持。该本地化包需要能够将所有可用的本地化文件合并为一个通用的本地化方案,从而创建一个包含所有内容类的接口。

在日常开发中,如果某个状态字段是 List<Object?>Map<Object, Object?> 类型,merger 可以用来更改状态。特别地,如果你需要在嵌套级别较深的地方更改或添加字段,或者只是需要合并 MapList 而不仅仅是第一层的深度时,merger 就显得非常有用。

如何使用merger

你可以通过两种方式来使用它——函数和扩展方法。

函数

Maps
import 'dart:convert';

import 'package:merger/merger.dart';

import 'deep_equals.dart';

final Map<Object, Object?> recipient = {
  'a': 1,
  'b': '2',
  'c': false,
  'd': null,
  'e': {
    'f': 3.5,
    'g': [
      '4',
      null,
      {
        'h': [false, true, 35.5],
        'i': {1: '5'}
      }
    ],
  }
};

final Map<Object, Object?> sender = {
  'a': [1, 2, 3],
  'c': 1,
  'e': {
    'g': [
      5,
      true,
      {
        'i': {'2': 6}
      },
      36,
    ]
  },
  'j': [123],
};

final Map<String, Object?> expected = {
  'a': [1, 2, 3],
  'b': '2',
  'c': 1,
  'd': null,
  'e': {
    'f': 3.5,
    'g': [
      5,
      true,
      {
        'h': [false, true, 35.5],
        'i': {1: '5', '2': 6}
      },
      36
    ]
  },
  'j': [123]
};

void main() {
  final Map<Object, Object?> result = mergeMaps(recipient, sender);

  print(deepEquals(expected, result)); // true
}
Lists
import 'package:merger/merger.dart';

import 'deep_equals.dart';
import 'main.dart' as m;

void main() {
  final List<Object?> recipient = [
    m.recipient,
  ];

  final List<Object?> sender = [
    m.sender,
  ];

  final List<Object?> result = mergeLists(recipient, sender);

  final List<Object?> expected = [
    m.expected,
  ];

  print(deepEquals(expected, result)); // true
}

扩展方法

import 'package:merger/merger.dart';

import 'deep_equals.dart';
import 'main.dart' as m;

void main() {
  final List<Object?> recipientList = [m.recipient];
  final List<Object?> senderList = [m.sender];

  final List<Object?> resultList = recipientList.mergeWith(senderList);

  final Map<Object, Object?> resultMap = m.recipient.mergeWith(m.sender);
}

配置

配置也可以通过两种方式进行。第二种方式补充了第一种,允许你以非常灵活的方式自定义合并策略(如果需要)。

函数/扩展方法参数

import 'package:merger/merger.dart';

import 'main.dart' as m;

void main() {
  final Map<Object, Object?> resultMap = m.recipient.mergeWith(
    m.sender,
    strategy: MergeStrategy.addAndOverride,
    resultBehavior: ResultBehavior.returnNew,
    listBehavior: ListBehavior.replaceWithNew,
    mapBehavior: MapBehavior.replaceWithNew,
    nullBehavior: NullBehavior.doNothing,
  );

  final List<Object?> resultList = [m.recipient].mergeWith(
    [m.sender],
    strategy: MergeStrategy.addAndOverride,
    resultBehavior: ResultBehavior.returnNew,
    listBehavior: ListBehavior.replaceWithNew,
    mapBehavior: MapBehavior.replaceWithNew,
    nullBehavior: NullBehavior.doNothing,
  );

  print(MergeStrategy.values); // [MergeStrategy.addOnly, MergeStrategy.overrideOnly, MergeStrategy.addAndOverride]
  print(ResultBehavior.values); // [ResultBehavior.returnNew, ResultBehavior.mergeWithOld]
  print(ListBehavior.values); // [ListBehavior.replaceWithNew, ListBehavior.valueByValue]
  print(MapBehavior.values); // [MapBehavior.replaceWithNew, MapBehavior.keyByKey]
  print(NullBehavior.values); // [NullBehavior.replace, NullBehavior.doNothing, NullBehavior.remove]
}

在Map或List参数中

你可以在要合并的 Map 或 List 的最后一个元素中或任何位置添加所需的参数。在这种情况下,整个子树配置将根据你指定的参数进行覆盖。

内联配置会覆盖在函数/扩展方法中定义的配置。并且每个新的内联配置会覆盖更高层级对象中定义的内联配置,但仅限于相同的参数变化。

你也可以在任何下一个层级中这样做。让我们来看一个例子:

final Map<String, Object?> recipient = {
  k1: '1',
  k2: 2,
  k3: 3.5,
  k4: false,
  k5: null,
  k6: {
    k1: '1',
    k2: 2,
    k3: 3.5,
    k4: true,
    k5: <Object>[],
    k6: ['6', 6, 6.5, false, null],
    k7: {
      k1: 1,
      k2: [
        2,
        true,
        [1, '2'],
      ],
    },
  },
};

final Map<String, Object?> donor = {
  k2: '2',
  k4: true,
  k6: {
    k1: '1',
    k3: 3.5,
    k5: <Object>[],
    k6: [
      null,
      '6',
      6.75,
      null,
      1,
      5,
      {
        NullBehavior.name: NullBehavior.remove.value, // [donor.k6.k6] and all its descendents will have [NullBehavior.remove]
      }
    ],
    k7: {
      k1: 1,
      k2: [
        2,
        true,
        [
          1,
          '2',
          {
            ListBehavior.name: ListBehavior.valueByValue, // (*) -> [donor.k6.k7.k2[2]] and all its descendents will have [ListBehavior.valueByValue]
            NullBehavior.name: NullBehavior.remove, // and also, [donor.k6.k7.k2[2]] and all its descendents will have [NullBehavior.remove]
            // and finally, [donor.k6.k7.k2[2]] and all its descendents still will have [MergeStrategy.addOnly]
          }
        ],
        [
          3,
          4,
        ],
      ],
      MergeSettings.name: {
        ListBehavior.name: ListBehavior.replaceWithNew, // [donor.k6.k7.k2] and all its descendents will have [ListBehavior.replaceWithNew], but ->
        MergeStrategy.name: MergeStrategy.addOnly, // and also, [donor.k6.k7.k2] and all its descendents will have [MergeStrategy.addOnly]
      },
    },
    k8: 31,
  },
  k7: {
    k9: 1,
    k10: [
      1,
      2,
      3,
      {
        ListBehavior.name: ListBehavior.replaceWithNew.value, // [donor.k7.k10] and all its descendents will have [ListBehavior.replaceWithNew]
      }
    ],
  },
};

final Map<String, Object?> mapInlineConfigurationExample = {
  // ...some values

  // Map inline configuration should be a [Map&lt;ParameterName, ParameterValue&gt;], defined by the key [MergeSettings.name]
  MergeSettings.name: {
    MergeStrategy.name: MergeStrategy.addOnly, // or any of [MergeStrategy.values]
    NullBehavior.name: NullBehavior.replace, // or any of [NullBehavior.values]
    MapBehavior.name: MapBehavior.keyByKey, // or any of [MapBehavior.values]
    ListBehavior.name: ListBehavior.valueByValue, // or any of [ListBehavior.values]
    ResultBehavior.name: ResultBehavior.returnNew, // or any of [ResultBehavior.values]
  },
};

final List<Object?> listInlineConfigurationExample = [
  // ...some values

  // List inline configuration should be a [Map&lt;ParameterName, ParameterValue&gt;], and the last value of the List
  {
    MergeStrategy.name: MergeStrategy.addOnly, // or any of [MergeStrategy.values]
    NullBehavior.name: NullBehavior.replace, // or any of [NullBehavior.values]
    MapBehavior.name: MapBehavior.keyByKey, // or any of [MapBehavior.values]
    ListBehavior.name: ListBehavior.valueByValue, // or any of [ListBehavior.values]
    ResultBehavior.name: ResultBehavior.returnNew, // or any of [ResultBehavior.values]
  },
];

限制

  1. 如果接收方 Map 或接收方 List 是 const List<Object?>const Map<Object, Object?>,那么如果你定义 [ResultBehavior][ResultBehavior.mergeWithOld],你将会得到一个错误,因为 merger 将尝试修改原始的常量接收方,这是不可能的。
  2. merger 只能合并 List<Object?>Map<Object, Object?>。所有其他数据类型将会被替换而不是合并。这意味着如果你的 Map 中有一个类,例如:
final a = {
  'a': SomeClass(),
};

final b = {
  'a': SomeClass2(),
};

final c = a.mergeWith(b); // {a: SomeClass2}

更多关于Flutter数据合并插件merger的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据合并插件merger的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,merger 插件通常用于合并数据集合,特别是在处理列表或复杂数据结构时非常有用。虽然 merger 不是一个官方或广泛认知的 Flutter 插件名称,但基于你的需求,我假设你指的是某种数据合并工具或自定义实现。为了提供一个相关的代码案例,我将展示如何在 Flutter 中实现一个简单的数据合并功能。

假设我们有两个数据源,一个是来自服务器的数据列表,另一个是本地缓存的数据列表,我们希望将它们合并成一个统一的数据列表。为了简化,我们将使用 Dart 语言的基本功能来实现这一点。

示例代码

数据模型

首先,定义一个简单的数据模型:

class Item {
  final String id;
  final String name;

  Item({required this.id, required this.name});

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Item && runtimeType == other.runtimeType && id == other.id;

  @override
  int get hashCode => id.hashCode;
}

数据合并函数

接下来,编写一个函数来合并两个数据列表。这里我们假设我们想要基于 id 属性来合并数据,如果 id 相同,我们则优先使用来自服务器的数据:

List<Item> mergeData(List<Item> serverData, List<Item> cacheData) {
  final Map<String, Item> mergedMap = <String, Item>{};

  // 添加服务器数据
  for (final item in serverData) {
    mergedMap[item.id] = item;
  }

  // 添加本地缓存数据,但仅当 `id` 不存在时
  for (final item in cacheData) {
    if (!mergedMap.containsKey(item.id)) {
      mergedMap[item.id] = item;
    }
  }

  // 返回合并后的列表
  return mergedMap.values.toList();
}

使用示例

最后,在 Flutter 应用中使用这个函数来合并数据:

void main() {
  // 示例数据
  List<Item> serverData = [
    Item(id: '1', name: 'Server Item 1'),
    Item(id: '2', name: 'Server Item 2'),
  ];

  List<Item> cacheData = [
    Item(id: '2', name: 'Cache Item 2 (older)'),
    Item(id: '3', name: 'Cache Item 3'),
  ];

  // 合并数据
  List<Item> mergedData = mergeData(serverData, cacheData);

  // 打印结果
  print('Merged Data:');
  for (final item in mergedData) {
    print('ID: ${item.id}, Name: ${item.name}');
  }
}

输出结果

运行上述代码,你将得到以下输出:

Merged Data:
ID: 1, Name: Server Item 1
ID: 2, Name: Server Item 2
ID: 3, Name: Cache Item 3

这个示例展示了如何将两个数据列表基于唯一标识符(id)进行合并,并优先使用来自服务器的数据。如果你提到的 merger 插件有特定的 API 或功能,你可能需要根据其文档进行调整。不过,上述代码提供了一个基础的数据合并实现,可以作为参考。

回到顶部