Kotlin泛型DataResponse中Success/Error类指定Nothing的原因解析
DataResponse<Nothing, R>和DataResponse<L, Nothing> 先明确父接口DataResponse<out L, out R>里的out关键字——这是Kotlin的协变标记,意思是泛型L和R只能作为返回值类型使用,并且如果A是B的子类,那么DataResponse<A, ...>可以安全向上转型为DataResponse<B, ...>,R同理。
接下来拆解两个实现类的写法逻辑:
Success类的
DataResponse<Nothing, R>
Success只负责承载成功数据R,完全不需要错误类型L。这里用Nothing作为L的类型参数,是因为Nothing是Kotlin的底部类型——它是所有类型的子类,没有任何实例。结合协变特性,Success<R>(也就是DataResponse<Nothing, R>)可以被当作任意DataResponse<任意错误类型, R>来使用。比如你需要一个DataResponse<ApiError, User>,Success<User>能直接兼容,因为Nothing是ApiError的子类,协变允许这种向上转型。如果这里不用Nothing,比如换成Unit,那当你需要DataResponse<ApiError, User>时,Success<User>就无法直接适配,因为Unit不是ApiError的子类,协变的优势就浪费了。Error类的
DataResponse<L, Nothing>
同理,Error只负责承载错误数据L,不需要成功类型R。用Nothing作为R的类型参数,同样利用它是所有类型子类的特性,让Error<L>可以被当作任意DataResponse<L, 任意成功类型>来使用。比如你需要DataResponse<ApiError, User>,Error<ApiError>(也就是DataResponse<ApiError, Nothing>)能直接兼容,因为Nothing是User的子类,协变规则允许这种转型。要是换成Unit,同样会出现类型不兼容的问题。
这种写法还能带来额外好处:当你用when表达式处理DataResponse时,Success分支里只能访问到R类型的成功数据,Error分支里只能访问到L类型的错误数据,不会出现无关类型,逻辑更清晰,同时保证了类型安全。
内容的提问来源于stack exchange,提问作者SHA

