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

无法为泛型方法创建Sourcery模板,求助泛型参数处理方案

解决Sourcery泛型方法Stub生成的问题

你的核心问题在于:Swift不允许存储属性携带泛型参数,而你当前的模板试图为泛型方法生成带泛型类型的存储属性,这在语法上是不合法的。因为泛型方法的<T: Codable>是调用时才确定的类型,而存储属性的类型必须在编译期固定。

下面提供两种可行的解决方案,适配不同的需求场景:

方案一:生成泛型设置方法(类型安全首选)

这种方式通过添加泛型的返回值设置方法,既保持类型安全,又适配泛型方法的动态类型需求。修改你的AutoStub.stencil模板如下:

{% macro methodStubSetName method -%}
set{{ method.callName | upperFirstLetter }}
{%- for param in method.parameters -%}
{{ param.name | upperFirstLetter }}
{%- endfor -%}ReturnValue
{%- endmacro -%}

{% macro methodGenericDeclaration method -%}
{% if method.isGeneric -%}
<{% for param in method.genericParameters %}{{ param.name }}: {{ param.constraints | join(", ") }}{% if not loop.last %}, {% endif %}{% endfor %}>
{%- endif -%}
{%- endmacro -%}

{% macro methodParametersWithTypes method -%}
{%- for param in method.parameters -%}
{{ param.name }}: {{ param.typeName }}{% if not loop.last %}, {% endif %}
{%- endfor -%}
{%- endmacro -%}

{% macro methodReturnName method -%}
{{ method.callName }}
{%- for param in method.parameters -%}
{{ param.name | upperFirstLetter }}
{%- endfor -%}_returnValue
{%- endmacro -%}

{% macro methodReturnType method -%}
{% if method.throws -%}
Result<{{ method.returnTypeName }}, Error>
{%- else -%}
{{ method.returnTypeName }}
{%- endif -%}
{%- endmacro -%}

public protocol {{ protocol.name }}Stubbing: {{ protocol.name }} {
{% for method in protocol.methods %}
    {%- if method.isGeneric -%}
    func {% call methodStubSetName method %}{% call methodGenericDeclaration method %}(_ value: {{ method.returnTypeName }}?, {% call methodParametersWithTypes method %})
    {%- else -%}
    var {% call methodReturnName method %}: {% call methodReturnType method %} { get set }
    {%- endif -%}
{% endfor %}
}

生成效果

对于你给出的get<T: Codable>(for key: String) -> T?方法,会生成如下Stub协议:

public protocol SomeProtocolStubbing: SomeProtocol {
    func setGetReturnValue<T: Codable>(_ value: T?, for key: String)
}

Stub实现示例

你可以这样实现Stub逻辑,用字典存储不同key对应的泛型返回值:

public class SomeProtocolStub: SomeProtocolStubbing {
    private var getReturnValues: [String: Any] = [:]
    
    func setGetReturnValue<T: Codable>(_ value: T?, for key: String) {
        getReturnValues[key] = value
    }
    
    func get<T: Codable>(for key: String) -> T? {
        return getReturnValues[key] as? T
    }
}

方案二:使用类型擦除的存储属性(简化场景)

如果追求模板的简洁性,可以将泛型方法的返回值存储改为字典类型,通过类型擦除来适配任意Codable类型。修改模板中的methodReturnNameAndType宏:

{% macro methodReturnNameAndType method -%}
{%- if method.isGeneric -%}
{% call methodReturnName method %}: [String: Any?] { get set }
{%- else -%}
{% call methodReturnName method %}: {% call methodReturnType method %} { get set }
{%- endif -%}
{%- endmacro -%}

生成效果

生成的Stub协议会是:

public protocol SomeProtocolStubbing {
    var getForKey_returnValue: [String: Any?] { get set }
}

Stub实现示例

public class SomeProtocolStub: SomeProtocolStubbing {
    var getForKey_returnValue: [String: Any?] = [:]
    
    func get<T: Codable>(for key: String) -> T? {
        return getForKey_returnValue[key] as? T
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:37:33