パッケージ、リポジトリ、アプリカテゴリを検索

パッケージ詳細v3.0.0

equatable

値ベースの等価性を明示的に == と hashCode をオーバーライドせずに実装するのを支援する Dart パッケージです。

AndroidiOSWebmacOSWindowsLinux
30日間ダウンロード
736万
いいね数
3640
Pub ポイント
160

パッケージをインストール

flutter pub add equatable

パッケージ概要

公開情報に基づく選定ガイドです。参考としてご利用ください。

Equatable は、オブジェクトのプロパティに基づいて自動的に == および hashCode メソッドを生成することで、値ベースの等価性の実装を簡素化するための Dart パッケージです。これらのメソッドを手動でオーバーライドする必要がなくなり、ボイラープレートコードを削減し、エラーのリスクも最小限に抑えます。モデルや状態、または等価性が識別子ではなくフィールド値に依存するクラスに最適です。このパッケージは Flutter および他の Dart プロジェクトとシームレスに統合され、コードの読みやすさと保守性を向上させます。

用途

  • ステート管理におけるモデルオブジェクトの比較
  • Redux や Bloc パターンにおける等価チェックの簡素化
  • データクラスにおけるボイラープレートの削減
  • リアクティブUIにおける状態変更の検証
  • コレクション内の一貫したハッシュ化を保証する

主な機能

  • 自動的な == および hashCode の生成
  • 最小限のボイラープレート
  • ネストされたおよび複雑な型のサポート
  • Flutter のステート管理との簡単な統合
  • ミックスインによって拡張可能

適している対象

  • Bloc や Redux を使用する開発者
  • クリーンで保守しやすいコードを重視するチーム
  • 頻繁なデータ比較が必要なプロジェクト
  • Dart開発者が手動の等価ロジックを回避する
  • 予測可能な状態の更新を必要とするアプリケーション

注意事項

  • ビルド時間をわずかに増加させる可能性があります
  • 参照に基づく等価性には適していない
  • null 値の取り扱いに注意が必要
  • 複雑な等価ルールに対するカスタマイズの制限
  • 不変データ構造と併用するのが最適です

元の README

関連するソースリポジトリの README 原文のスナップショットです。最新の内容はリポジトリをご覧ください。

logo

Simplify Equality Comparisons

Build Status Code Coverage Pub Package
Star on GitHub Discord MIT License


Overview

Being able to compare objects in Dart often involves having to override the == operator as well as hashCode.

Not only is it verbose and tedious, but failure to do so can lead to inefficient code which does not behave as we expect.

By default, == returns true if two objects are the same instance.

Let's say we have the following class:

class Person {
  const Person(this.name);

  final String name;
}

We can create instances of Person like so:

void main() {
  final Person bob = Person("Bob");
}

Later if we try to compare two instances of Person either in our production code or in our tests we will run into a problem.

print(bob == Person("Bob")); // false

For more information about this, you can check out the official Dart Documentation.

In order to be able to compare two instances of Person we need to change our class to override == and hashCode like so:

class Person {
  const Person(this.name);

  final String name;

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

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

Now if we run the following code again:

print(bob == Person("Bob")); // true

it will be able to compare different instances of Person.

You can see how this can quickly become a hassle when dealing with complex classes. This is where Equatable comes in!

What does Equatable do?

Equatable overrides == and hashCode for you so you don't have to waste your time writing lots of boilerplate code.

There are other packages that will actually generate the boilerplate for you; however, you still have to run the code generation step which is not ideal.

With Equatable there is no code generation needed and we can focus more on writing amazing applications and less on mundane tasks.

Usage

First, we need to do add equatable to the dependencies of the pubspec.yaml

dependencies:
  equatable: ^3.0.0

Next, we need to install it:

# Dart
dart pub get

# Flutter
flutter packages get

Lastly, we need to extend Equatable

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name);

  final String name;

  @override
  List<Object> get props => [name];
}

When working with json:

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name);

  final String name;

  @override
  List<Object> get props => [name];

  factory Person.fromJson(Map<String, dynamic> json) {
    return Person(json['name']);
  }
}

We can now compare instances of Person just like before without the pain of having to write all of that boilerplate. Note: Equatable is designed to only work with immutable objects so all member variables must be final (This is not just a feature of Equatable - overriding a hashCode with a mutable value can break hash-based collections).

Equatable also supports const constructors:

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name);

  final String name;

  @override
  List<Object> get props => [name];
}

Equatable also supports nullable props:

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name, [this.age]);

  final String name;
  final int? age;

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

Equatable can implement toString method including all the given props. If you want that behaviour for a specific Equatable object, just include the following:

@override
bool get stringify => true;

For instance:

import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name);

  final String name;

  @override
  List<Object> get props => [name];

  @override
  bool get stringify => true;
}

For the name Bob, the output will be:

Person(Bob)

This flag by default is false and toString will fallback to the default implementation:

Instance of Person

EquatableConfig

stringify can also be configured globally for all Equatable instances via EquatableConfig

EquatableConfig.stringify = true;

If stringify is overridden for a specific Equatable class, then the value of EquatableConfig.stringify is ignored. In other words, the local configuration always takes precedence over the global configuration.

Note: EquatableConfig.stringify defaults to true in debug mode and false in release mode.

Recap

Without Equatable
class Person {
  const Person(this.name);

  final String name;

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

  @override
  int get hashCode => name.hashCode;
}
With Equatable
import 'package:equatable/equatable.dart';

class Person extends Equatable {
  const Person(this.name);

  final String name;

  @override
  List<Object> get props => [name];
}

Mixin Usage

Sometimes it isn't possible to extend Equatable because your class already has a superclass. In this case, you can still get the benefits of Equatable by using Equatable as a mixin.

Usage

Let's say we want to make an EquatableDateTime class, we can use Equatable like so:

class EquatableDateTime extends DateTime with Equatable {
  EquatableDateTime(
    int year, [
    int month = 1,
    int day = 1,
    int hour = 0,
    int minute = 0,
    int second = 0,
    int millisecond = 0,
    int microsecond = 0,
  ]) : super(year, month, day, hour, minute, second, millisecond, microsecond);

  @override
  List<Object> get props {
    return [year, month, day, hour, minute, second, millisecond, microsecond];
  }
}

Now if we want to create a subclass of EquatableDateTime, we can just override props.

class EquatableDateTimeSubclass extends EquatableDateTime {
  final int century;

  EquatableDateTimeSubclass(
    this.century,
    int year,[
    int month = 1,
    int day = 1,
    int hour = 0,
    int minute = 0,
    int second = 0,
    int millisecond = 0,
    int microsecond = 0,
  ]) : super(year, month, day, hour, minute, second, millisecond, microsecond);

  @override
  List<Object> get props => [...super.props, century];
}

Benchmarks

You can see and run performance benchmarks by heading over to benchmarks.

Maintainers

カテゴリー

依存関係

依存関係一覧 2 件

ソースリポジトリ

このパッケージを使用しているプロジェクト

ランキング