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

如何判断Kotlin泛型类型是否可为空?Retrofit映射问题求助

处理Retrofit Response映射Resource时201无响应体的问题

你编写的Retrofit Response转Resource的内联函数,在API返回201状态码且无响应体时会误判为Error,但这类场景(比如资源创建成功)属于正常业务成功情况,下面提供两种可行的修改方案:

方案一:基于状态码+泛型可空性适配

Retrofit的isSuccessful包含200-299所有成功状态码,但像201(创建成功)、204(无内容)这类状态码本身就允许无响应体。我们可以针对这类状态码做特殊处理,同时判断泛型是否支持空值:

inline fun <reified T> Response<T>.mapToResource(): Resource<T> {
    return if (isSuccessful) {
        val body = body()
        when {
            // 匹配HTTP标准中允许无响应体的成功状态码
            code() in 201..204 -> {
                // 判断泛型T是否为可空类型,是的话返回带null的Success
                if (null is T) {
                    @Suppress("UNCHECKED_CAST")
                    Resource.Success(null as T)
                } else {
                    // 泛型不可为空时,根据业务选择:要么提示无数据,要么返回默认值
                    Log.w("Resource", "API返回成功状态码(${code()})但无响应体,泛型不可为空")
                    Resource.Error("操作成功但无返回数据")
                }
            }
            body != null -> Resource.Success(body)
            else -> {
                Log.e("Resource", "API返回成功但无可用数据")
                Resource.Error("API返回成功但无可用数据")
            }
        }
    } else {
        val errorMsg = message().takeIf { it.isNotEmpty() } ?: "请求失败,状态码:${code()}"
        Log.e("Resource", errorMsg)
        Resource.Error(errorMsg)
    }
}

说明

  • 优先匹配201-204区间的状态码,这类场景下无响应体是符合HTTP规范的
  • 通过null is T判断泛型是否支持空值,适配Resource<Unit?>或Resource<Void?>这类无数据返回的接口定义
  • 若泛型不可为空但遇到无响应体的成功状态,可根据业务需求调整逻辑(比如返回默认值而非Error)

方案二:扩展Resource密封类,新增无数据成功类型

如果业务中频繁出现无数据的成功场景,建议给Resource新增一个语义明确的EmptySuccess类型,避免依赖泛型可空性:

首先调整Resource密封类定义:

sealed class Resource<out T> {
    data class Success<out T>(val data: T) : Resource<T>()
    object EmptySuccess : Resource<Nothing>() // 专门用于无数据的成功场景
    data class Error(val message: String) : Resource<Nothing>()
}

然后修改映射函数:

inline fun <reified T> Response<T>.mapToResource(): Resource<T> {
    return if (isSuccessful) {
        val body = body()
        when {
            code() in 201..204 -> Resource.EmptySuccess as Resource<T>
            body != null -> Resource.Success(body)
            else -> {
                Log.e("Resource", "API返回成功但无可用数据")
                Resource.Error("API返回成功但无可用数据")
            }
        }
    } else {
        val errorMsg = message().takeIf { it.isNotEmpty() } ?: "请求失败,状态码:${code()}"
        Log.e("Resource", errorMsg)
        Resource.Error(errorMsg)
    }
}

说明

  • EmptySuccess明确标识“操作成功但无数据返回”的场景,调用方处理时可以清晰区分不同成功状态,避免null带来的潜在问题
  • 这种方式语义更清晰,适合业务中大量存在创建、删除等无需返回数据的接口场景

总结

  • 若只是偶尔遇到201无响应体的情况,方案一足够灵活,不需要修改Resource类结构
  • 若这类场景较多,方案二更优,通过明确的状态类型减少后续维护的歧义

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:03:26