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

Swift中能否像TypeScript那样定义方法依赖泛型的结构体?关联类型协议的方法签名适配需求

实现依赖泛型类型的方法签名调整

当然可以实现这个需求!在Swift中,我们可以利用协议扩展结合泛型关联类型约束,为UseCase协议根据Request类型的不同提供差异化的方法签名和实现,让Request为Void时能使用更简洁的无参数execute方法。

完整实现方案

首先保留你原有的协议定义,然后通过协议扩展来实现逻辑分支:

protocol UseCase {
    associatedtype Request
    associatedtype Response
    func execute(controller: () throws -> Request) async throws -> Response
}

// 为非Void的Request类型提供默认实现(或留空让遵循者自行实现)
extension UseCase {
    func execute(controller: () throws -> Request) async throws -> Response {
        fatalError("请为非Void类型的UseCase实现execute(controller:)方法")
    }
}

// 针对Request为Void的情况,添加无参数的execute方法并兼容原方法
extension UseCase where Request == Void {
    // 提供无参数的重载方法,这是我们期望的简洁调用方式
    func execute() async throws -> Response {
        // 调用原方法,传入空闭包生成Void值
        try await execute(controller: { () })
    }
    
    // 为原方法提供默认实现,调用无参数版本,避免遵循者重复编写逻辑
    func execute(controller: () throws -> Void) async throws -> Response {
        try await execute()
    }
}

用法示例

接下来我们分别实现两种类型的UseCase,验证效果:

1. Request为Void的场景

struct FetchStatusUseCase: UseCase {
    typealias Request = Void
    typealias Response = String
    
    // 只需要实现无参数的execute方法即可
    func execute() async throws -> String {
        await Task.sleep(UInt64(0.5 * 1_000_000_000))
        return "当前状态正常"
    }
}

// 调用时直接使用无参数语法
Task {
    let useCase = FetchStatusUseCase()
    do {
        let status = try await useCase.execute()
        print(status) // 输出:当前状态正常
    } catch {
        print(error)
    }
}

2. Request为非Void的场景

struct FetchUserUseCase: UseCase {
    typealias Request = Int
    typealias Response = String
    
    // 实现带controller参数的原方法
    func execute(controller: () throws -> Int) async throws -> String {
        let userId = try controller()
        await Task.sleep(UInt64(0.5 * 1_000_000_000))
        return "获取到用户ID:\(userId)"
    }
}

// 调用时需要传入生成Request的闭包
Task {
    let useCase = FetchUserUseCase()
    do {
        let userInfo = try await useCase.execute(controller: { 1001 })
        print(userInfo) // 输出:获取到用户ID:1001
    } catch {
        print(error)
    }
}

原理说明

  • 协议扩展的where子句让我们可以精准定位到Request == Void的场景,为其添加专属的无参数execute重载方法。
  • Swift的方法重载解析会优先匹配最具体的签名,所以当Request为Void时,调用execute()会直接命中我们添加的重载,而非原协议的带参方法。
  • 我们同时为原带参方法提供了默认实现,调用无参数版本,这样遵循协议的类型只需要实现一种方法即可,避免重复逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:59:07