无法为泛型方法创建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
相关产品推荐
相关产品推荐

