Flutter高效对象比较插件fast_equatable的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter高效对象比较插件fast_equatable的使用

概述

这是一个简单的Dart包,提供了快速且安全的对象相等性比较功能,作为mixin实现。这为现有的代码提供了良好的兼容性。

它还提供了可选的哈希缓存功能,以显著提高例如MapSet的速度。

默认情况下,使用的是广泛传播的詹金斯散列函数,但你也可以实现并提供自己的哈希引擎,以满足你的需求。

任何类型的对象都可以放入hashParameters。默认支持简单类型和标准集合,如ListIterableMapSet。当你使用自定义类时,请确保也使用FastEquatable mixin,或者至少重写hashCodeoperator ==方法。

示例

class FastEquatableCached with FastEquatable {
  final String value1;
  final List<String>? value2;

  FastEquatableCached(this.value1, this.value2);

  [@override](/user/override)
  // 这是一个不可变对象,所以我们想要缓存哈希值
  bool get cacheHash => true;

  [@override](/user/override)
  List<Object?> get hashParameters => [value1, value2];
}

性能测试

example文件夹中,你可以找到一个性能测试代码,展示了由此带来的速度提升。

equatable for 1000000 elements(RunTime): 8583044.5 us.
fast_equatable (uncached) for 1000000 elements(RunTime): 8493327.5 us.
fast_equatable (cached) for 1000000 elements(RunTime): 3329455.5 us.

完整示例代码

import 'dart:math';

import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:equatable/equatable.dart';
import 'package:fast_equatable/fast_equatable.dart';

// 使用FastEquatable mixin的带缓存的类
class FastEquatableCached with FastEquatable {
  final String value1;
  final List<String>? value2;

  FastEquatableCached(this.value1, this.value2);

  [@override](/user/override)
  // 这是一个不可变对象,所以我们想要缓存哈希值
  bool get cacheHash => true;

  [@override](/user/override)
  List<Object?> get hashParameters => [value1, value2];
}

// 使用FastEquatable mixin的不带缓存的类
class FastEquatableUncached with FastEquatable {
  final String value1;
  final List<String>? value2;

  FastEquatableUncached(this.value1, this.value2);

  [@override](/user/override)
  // 不需要缓存哈希值
  bool get cacheHash => false;

  [@override](/user/override)
  List<Object?> get hashParameters => [value1, value2];
}

// 使用Equatable库的类
class TestClassEquatable extends Equatable {
  final String value1;
  final List<String>? value2;

  const TestClassEquatable(this.value1, this.value2);

  [@override](/user/override)
  List<Object?> get props => [value1, value2];
}

// 基准测试基类
abstract class BenchmarkBase extends BenchmarkBase {
  final List<String> _randsValA;
  final List<String> _randsValB;

  late final List<TestClassEquatable> objects;

  BenchmarkBase(this._randsValA, this._randsValB)
      : assert(_randsValA.length == _randsValB.length),
        super('基准测试');

  [@override](/user/override)
  void setup() {
    objects = List.generate(_randsValA.length,
        (i) => TestClassEquatable(_randsValA[i], [_randsValB[i]]));
  }

  [@override](/user/override)
  void run() {
    final set = <TestClassEquatable>{};

    for (final obj in objects) {
      set.add(obj);
    }
  }
}

// 使用Equatable库的基准测试类
class EquatableBenchmark extends BenchmarkBase {
  EquatableBenchmark(super._randsValA, super._randsValB)
      : super('equatable for ${_randsValA.length} elements');

  [@override](/user/override)
  void run() {
    final set = <TestClassEquatable>{};

    for (final obj in objects) {
      set.add(obj);
    }
  }
}

// 使用FastEquatable不带缓存的基准测试类
class FastEquatableUncachedBenchmark extends BenchmarkBase {
  FastEquatableUncachedBenchmark(super._randsValA, super._randsValB)
      : super('fast_equatable (uncached) for ${_randsValA.length} elements');

  [@override](/user/override)
  void run() {
    final set = <FastEquatableUncached>{};

    for (final obj in objects) {
      set.add(obj);
    }
  }
}

// 使用FastEquatable带缓存的基准测试类
class FastEquatableCachedBenchmark extends BenchmarkBase {
  FastEquatableCachedBenchmark(super._randsValA, super._randsValB)
      : super('fast_equatable (cached) for ${_randsValA.length} elements');

  [@override](/user/override)
  void run() {
    final set = <FastEquatableCached>{};

    for (final obj in objects) {
      set.add(obj);
    }
  }
}

void main(List<String> args) {
  const int nAcc = 1000000;

  final rand = Random();
  final randsVal1 = List.generate(nAcc, (_) => rand.nextInt(nAcc).toString());
  final randsVal2 = List.generate(nAcc, (_) => rand.nextInt(nAcc).toString());

  EquatableBenchmark(randsVal1, randsVal2).report();
  FastEquatableUncachedBenchmark(randsVal1, randsVal2).report();
  FastEquatableCachedBenchmark(randsVal1, randsVal2).report();
}

更多关于Flutter高效对象比较插件fast_equatable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter高效对象比较插件fast_equatable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用fast_equatable插件进行高效对象比较的示例代码。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加fast_equatable依赖:

dependencies:
  flutter:
    sdk: flutter
  fast_equatable: ^3.0.0  # 请根据需要检查最新版本号

然后运行flutter pub get来安装依赖。

2. 创建一个数据模型

接下来,创建一个数据模型,并让它继承Equatable类。Equatable类来自fast_equatable包,它允许你通过指定哪些字段用于比较对象是否相等。

import 'package:fast_equatable/fast_equatable.dart';

class User extends Equatable {
  final String id;
  final String name;
  final int age;

  User({required this.id, required this.name, required this.age});

  @override
  List<Object?> get props => [id, name, age];
}

在上面的代码中,User类有三个属性:idnameageprops getter方法返回一个包含用于比较的字段的列表。

3. 使用对象比较

现在你可以创建User对象并使用==运算符或===运算符(对于引用比较)来比较它们。由于我们使用了Equatable==运算符会比较props中指定的字段。

void main() {
  User user1 = User(id: '1', name: 'Alice', age: 30);
  User user2 = User(id: '1', name: 'Alice', age: 30);
  User user3 = User(id: '2', name: 'Bob', age: 25);

  print(user1 == user2); // 输出: true
  print(user1 == user3); // 输出: false
}

在上面的代码中,user1user2具有相同的属性值,因此它们被认为是相等的。而user3的属性值与user1不同,所以它们不相等。

4. 在Flutter Widget中使用

你也可以在Flutter Widget中使用这些对象,并进行比较。例如,在ListView.builder中渲染用户列表,并根据某些条件更新UI。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('fast_equatable Example')),
        body: UserList(),
      ),
    );
  }
}

class UserList extends StatefulWidget {
  @override
  _UserListState createState() => _UserListState();
}

class _UserListState extends State<UserList> {
  List<User> users = [
    User(id: '1', name: 'Alice', age: 30),
    User(id: '2', name: 'Bob', age: 25),
  ];

  void _addUser() {
    setState(() {
      users.add(User(id: '3', name: 'Charlie', age: 35));
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Expanded(
          child: ListView.builder(
            itemCount: users.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text('${users[index].name} (${users[index].age})'),
              );
            },
          ),
        ),
        ElevatedButton(
          onPressed: _addUser,
          child: Text('Add User'),
        ),
      ],
    );
  }
}

在这个例子中,我们创建了一个简单的Flutter应用,它显示了一个用户列表,并允许你通过点击按钮添加新用户。由于我们使用了fast_equatable,所以Flutter框架可以高效地比较User对象,并在必要时更新UI。

希望这个示例代码能帮助你理解如何在Flutter项目中使用fast_equatable进行高效对象比较。

回到顶部