搜尋套件、儲存庫與 APP 分類

套件詳情v5.3.0

multiple_result

dart 的多個結果。受到 dartz 的 Either 和 Kotlin 的密封類別啟發

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
4.5萬
喜歡數
174
Pub 分數
160

安裝套件

flutter pub add multiple_result

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

Multiple_result 是一個 Dart 套件,提供一種強大且類型安全的方式來處理多種可能的結果,靈感來自 dartz 的 Either 與 Kotlin 的密封類別。它讓開發者能以多種成功或失敗狀態來建模複雜的結果類型,提升程式碼清晰度與錯誤處理能力。此套件支援完整的模式比對,並設計用於所有主要平台,非常適合在 Flutter 及其他 Dart 應用程式中進行函數式程式設計。

適用情境

  • API 中處理多個成功或錯誤狀態
  • 使用清晰的結果類型實現狀態管理
  • 透過明確的結果建構具彈性的業務邏輯
  • 在Dart中支援函數式程式設計模式
  • 使用不同結果管理非同步操作

主要特色

  • 支援多種結果類型
  • 詳盡的模式比對
  • 類型安全的結果處理
  • 受到 Kotlin sealed classes 和 dartz Either 的啟發
  • 跨平台相容性

適合對象

  • 使用函數式程式設計的Dart開發者
  • 優先考慮類型安全和錯誤處理的團隊
  • Flutter 應用需要結構化結果管理
  • 具有複雜狀態轉換的專案

使用建議

  • 需要理解函數式概念
  • 可能增加簡單情況下的樣板程式碼
  • 最適合具有複雜工作流程的大型應用程式
  • 對於沒有多個變體的基本成功/失敗場景來說並不理想

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

multiple_result

A Result package for Dart inspired by dartz's Either type and Kotlin's sealed classes.

This package is perfect for those who just want the multiple results functionality from dartz. 👌

Using the Result type:

In your function signature, declare it to return a Result type:

Result getSomething();

Then specify the Success and Error types:

Result<String, Exception> getSomething() {

}

When returning from the function, simply use:

return Success('Success!');

or

return Error(Exception('Some error happened...'));

A complete function looks like this:

Future<Result<String, Exception>> getSomething() async {
    
    try {
      final response = await _api.get('/foo');
      final data = response.data['bar'];
      return Success(data);
    } catch(e) {
      return Error(e);
    }
}
Handling Results
Using switch:
void main() {
  final result = getSomething();
  switch(result) {
    case Success():
      print("${result.success}");
      break;
    case Error():
      print("${result.error}");
      break;
  }
}

Or with Switch Expression:

  final result = await getSomething();
  final output = switch (result) {
    Success(success: var s) => processSuccess(s),
    Error(error: var e) => handleError(e)
  };
Using when:
void main() {
    final result = await getSomething();
    final String message = result.when(
        (data) {
          // handle the success here
          return "Successfully fetched data: $data";
        },
        (error) {
          // handle the error here
          return "error: $error";
        },
    );
}
Using if case:
void main() {
  final result = getSomething();
  if(result case Success()) {
    // access to .success value
    print("${result.success}");
  }
}
Using whenSuccess or whenError
    final result = getSomethingPretty();
    // Note that [whenSuccess] or [whenError] will only be executed if
    // the result is a Success or an Error respectively. 
    final output = result.whenSuccess((name) {
        // handle here the success
        return "";
    });
    
    final result = getSomethingPretty();
    
    // If [result] is NOT an Error, this [output] will be null.
    final output = result.whenError((exception) {
        // handle here the error
        return "";
    });
Using getOrThrow

You can use getOrThrow to get the value when you're sure that the result is a Success. Be aware that calling this method when the result is actually an Error will throw a SuccessResultNotFoundException.

    final result = await getSomething();

    if (result.isSuccess()) {
      // Here, you can "safely" get the success result as it was verified in the previous line.
      final mySuccessResult = result.getOrThrow();
    }
Using tryGetSuccess
void main() {
    final result = getSomethingPretty();

    String? mySuccessResult;
    if (result.isSuccess()) {
      mySuccessResult = result.tryGetSuccess();
    }
}
Using tryGetError
void main() {
    final result = getSomethingPretty();

    Exception? myException;
    if (result.isError()) {
      myException = result.tryGetError();
    }
}

Using getBoth

The getBoth method returns a record (Dart's named tuple) containing both the success and error values of a Result. Only one of these will be non-null, depending on whether the result is a Success or an Error.

  • If the result is a Success, the success field will contain the value, and error will be null.
  • If the result is an Error, the error field will contain the error, and success will be null.

This is useful for destructuring or pattern matching without having to check the type explicitly.

Example:

void main() {
  final result = getSomething();
  final (:success, :error) = result.getBoth();
  
  if (success != null) {
    print("Success: $success");
  } else {
    print("Error: $error");
  }
}

Transforming Results

The Result class provides several methods for transforming values while preserving the success/error structure:

Using map

The map method transforms both the success and error values of a Result:

Result<int, Exception> result = fetchNumber();
Result<String, String> transformed = result.map(
  successMapper: (number) => number.toString(),
  errorMapper: (exception) => exception.toString()
);
Using mapSuccess

The mapSuccess method transforms only the success value, preserving any error:

Result<int, Exception> result = fetchNumber();
Result<String, Exception> transformed = result.mapSuccess(
  (number) => number.toString()
);
Using mapError

The mapError method transforms only the error value, preserving any success:

Result<int, Exception> result = fetchNumber();
Result<int, String> transformed = result.mapError(
  (exception) => exception.toString()
);
Using flatMap

The flatMap method is powerful for chaining operations that can fail. Unlike mapSuccess which wraps the returned value in a Result, flatMap expects your function to return a Result directly:

Result<int, String> fetchNumber() => Success(5);

Result<String, String> parseNumber(int n) {
  if (n > 0) {
    return Success(n.toString());
  } else {
    return Error("Cannot parse negative numbers");
  }
}

// Chain operations that might fail
Result<String, String> result = fetchNumber().flatMap(
  (number) => parseNumber(number)
);

The key difference between mapSuccess and flatMap:

  • mapSuccess takes a function that returns a value T and wraps it in a Result
  • flatMap takes a function that returns a Result directly, avoiding nested Results
Using Result.tryCatch

Replace try/catch blocks with Result.tryCatch to convert a throwing operation directly into a Result:

final result = Result.tryCatch(
  () => int.parse(userInput),
  (error, stackTrace) => ParseError(error.toString()),
);
// result is Success(42) or Error(ParseError(...))
Using getOrElse

Provide a fallback value computed from the error instead of throwing:

final value = result.getOrElse((error) => defaultValue);
Using onSuccess / onError

Run side effects (e.g. logging) in the middle of a chain without breaking it:

result
    .onSuccess((data) => logger.info('Got $data'))
    .onError((error) => logger.error('Failed: $error'))
    .mapSuccess((data) => data.toUpperCase());
Using flatMapError / recover

Handle errors and recover into a new Result, symmetric to flatMap:

final result = fetchUser(id)
    .flatMapError((e) => fetchUserFromCache(id));

// or with the alias:
final result = fetchUser(id)
    .recover((e) => fetchUserFromCache(id));
Using swap

Convert a Success into an Error and vice versa — useful for inverting validation logic:

final inverted = result.swap();
// Success('x') becomes Error('x'), Error(e) becomes Success(e)

Async Results with AsyncResult

AsyncResult<S, E> is a zero-cost wrapper around Future<Result<S, E>> using Dart extension types. It lets you chain transformations on async results fluently without awaiting at each step.

// Wrap a Future<Result> as AsyncResult
AsyncResult<User, ApiError> fetchUser(int id) =>
    AsyncResult(api.get('/users/$id').then((r) => r.toResult()));

// Chain operations without intermediate awaits
final greeting = await fetchUser(42)
    .mapSuccess((user) => user.name.toUpperCase())
    .onError((e) => logger.error('Failed: $e'))
    .getOrElse((_) => 'Anonymous');

Use AsyncResult.tryCatch to wrap a potentially-throwing async function:

final result = AsyncResult.tryCatch(
  () async => await api.fetchUser(id),
  (error, stack) => NetworkError(error.toString()),
);

Use flatMapAsync to chain operations that are themselves async:

final result = fetchUser(42)
    .flatMapAsync((user) => fetchPosts(user.id));

Unit Type

Some results don't need a specific return value. Use the Unit type to signal an empty return:

    Result<Unit, Exception>

ResultOf

You may have noticed the ResultOf typedef. It represents a more readable alternative for Result.

所屬分類

原始碼儲存庫

使用此套件的專案