You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart中Resource泛型类型不兼容问题及实现方案咨询

解决Dart中Resource泛型类错误处理的类型不匹配问题

你的核心问题在于泛型约束的对齐错误:原代码中FutureResourceExt的泛型T extends Resource没有明确绑定Resource的泛型参数,导致错误时返回的Resource<dynamic>无法匹配实际需要的Resource<S>类型,强制转换又会因为泛型参数不兼容触发运行时异常。

修正方案

我们需要将扩展和错误处理逻辑明确绑定到Resource<S>的具体泛型实例上,不需要提前知晓S的具体类型,只需要保证错误实例的泛型参数与成功实例一致即可。

1. 调整扩展与错误处理逻辑

将原来的FutureResourceExt改为针对Future<Resource<S>>的扩展,让错误返回的Resource实例泛型参数与原Future的类型一致:

extension FutureResourceExt<S> on Future<Resource<S>> {
  Future<Resource<S>> useErrorHandler() {
    return onError((error, stacktrace) => Resource<S>.error("Error: $error"));
  }
}

如果需要保留单独的handleError函数,也可以修改为带泛型参数的版本:

Resource<S> handleError<S>(dynamic error) {
  return Resource<S>.error("Error: $error");
}

// 扩展中调用
extension FutureResourceExt<S> on Future<Resource<S>> {
  Future<Resource<S>> useErrorHandler() {
    return onError((error, stacktrace) => handleError<S>(error));
  }
}

2. 优化Resource类的空安全性(可选)

原代码中data和error的getter使用!强制解包存在崩溃风险,可以优化为更安全的写法:

class Resource<S> {
  final S? _data;
  final String? _message;

  Resource.success(S data)
      : _data = data,
        _message = null;

  Resource.error(String message)
      : _data = null,
        _message = message;

  bool get isError => _message != null;

  // 仅当非错误时才返回有效数据,否则抛出异常
  S get data {
    if (isError) throw StateError("Cannot access data in error state");
    return _data!;
  }

  // 仅当错误时才返回错误信息,否则抛出异常
  String get error {
    if (!isError) throw StateError("Cannot access error in success state");
    return _message!;
  }
}

修正后的完整代码

/// Fetches data from TestRepository and shows result
main () async {
  final repository = TestRepository();
  final resource = await repository.fetchString();
  if (resource.isError) {
    print("| Error: ${resource.error}");
  } else {
    print("| Success: ${resource.data}");
  }
}

/// A class to get Success or Error responses
class Resource<S> {
  final S? _data;
  final String? _message;

  Resource.success(S data)
      : _data = data,
        _message = null;

  Resource.error(String message)
      : _data = null,
        _message = message;

  bool get isError => _message != null;

  S get data {
    if (isError) throw StateError("Cannot access data in error state");
    return _data!;
  }

  String get error {
    if (!isError) throw StateError("Cannot access error in success state");
    return _message!;
  }
}

/// A sample repository class to use API and handle errors
class TestRepository {
  Future<Resource<String>> fetchString() {
    return _dummyApiCall().useErrorHandler();
  }

  /// Dummy API Call mimicking
  Future<Resource<String>> _dummyApiCall() async {
    await Future.delayed(const Duration(seconds: 1));
    if (true) {
      // to mimic an exception so that we can catch it
      throw Exception("Error Occurred");
    }
    return Resource.success("Hello World");
  }
}

/// An extension to wrap Resource Futures with error handler
extension FutureResourceExt<S> on Future<Resource<S>> {
  Future<Resource<S>> useErrorHandler() {
    return onError((error, stacktrace) => Resource<S>.error("Error: $error"));
  }
}

为什么原方案会失败?

原代码中T extends Resource是未指定泛型参数的原始类型,Dart会将其视为Resource<dynamic>。而你的fetchString返回的是Future<Resource<String>>,此时T实际代表Resource<String>,但handleError返回的是Resource<dynamic>,两者属于不同的泛型实例,无法直接赋值;强制转换as T会因为泛型参数不兼容触发运行时异常——Dart中Resource<dynamic>和Resource<String>是不兼容的类型。

内容的提问来源于stack exchange,提问作者rupinderjeet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 14:48:23