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

如何从嵌套类型链中获取字符串路径?无需重复编写计算属性

如何避免在每个API分组枚举中重复编写路径生成逻辑?

我把服务端API按分组划分到ServerApi结构体的多个枚举中,但每个枚举都需要重复编写相同的string计算属性来生成完整API路径,示例代码如下:

struct ServerApi {
    enum Auth {
        case login
        case logout
        
        var string: String {
            "/\(Self.self)".lowercased() + "/\(self)"
        }
    }
    enum App {
        case version
        case webapiVersion
        case buildInfo
        
        var string: String {
            "/\(Self.self)".lowercased() + "/\(self)"
        }
    }
    
    enum GroupA {
        case versionA
        case webapiVersionA
        case buildInfoA
        
        var string: String {
            "/\(Self.self)".lowercased() + "/\(self)"
        }
    }
}

有没有办法不用在每个枚举里重复写这个计算属性?


解决方案:利用协议扩展实现通用路径生成逻辑

可以通过定义一个通用协议,并在协议扩展中实现默认的路径生成逻辑,让所有API分组枚举只需遵守该协议即可自动获得路径生成能力,彻底消除重复代码。

实现步骤:

  1. 定义协议声明路径属性
  2. 在协议扩展中编写通用的路径计算逻辑
  3. 让每个API分组枚举遵守该协议

完整代码示例:

// 定义通用协议
protocol ApiGroup {
    var fullPath: String { get }
}

// 协议扩展:实现默认的路径生成逻辑
extension ApiGroup {
    // 获取分组名(枚举名转小写)
    private static var groupPath: String {
        "/\(String(describing: Self.self))".lowercased()
    }
    
    // 生成完整API路径
    var fullPath: String {
        let caseName = String(describing: self)
        return Self.groupPath + "/\(caseName)"
    }
}

// 重构后的ServerApi结构体,每个枚举只需遵守ApiGroup协议
struct ServerApi {
    enum Auth: ApiGroup {
        case login
        case logout
    }
    
    enum App: ApiGroup {
        case version
        case webapiVersion
        case buildInfo
    }
    
    enum GroupA: ApiGroup {
        case versionA
        case webapiVersionA
        case buildInfoA
    }
}

使用方式:

调用时直接访问枚举case的fullPath属性即可:

let loginPath = ServerApi.Auth.login.fullPath // 输出:"/auth/login"
let versionPath = ServerApi.App.webapiVersion.fullPath // 输出:"/app/webapiVersion"

可选优化:驼峰转下划线

如果需要将枚举case的驼峰命名转换为下划线格式(比如webapiVersion转成webapi_version),可以给String添加扩展并修改协议逻辑:

// 字符串扩展:驼峰转下划线
extension String {
    func camelCaseToSnakeCase() -> String {
        let pattern = "([a-z0-9])([A-Z])"
        return self.replacingOccurrences(of: pattern, with: "$1_$2", options: .regularExpression).lowercased()
    }
}

// 修改协议扩展中的fullPath实现
extension ApiGroup {
    var fullPath: String {
        let caseName = String(describing: self).camelCaseToSnakeCase()
        return Self.groupPath + "/\(caseName)"
    }
}

此时ServerApi.App.webapiVersion.fullPath会输出"/app/webapi_version"。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 13:07:44