问题描述
我使用此扩展名是为了在urlSession回调中检索HTTP标头:
I'm using this extension in order to retrieve HTTP headers within a urlSession callback:
extension HTTPURLResponse {
func get(_ header: String) -> String? {
let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }
if let headerValue = keyValues.filter({ $0.0 == header.lowercased() }).first {
return headerValue.1
}
return nil
}
}
这很好用,让我可以像这样检索标头元素:
This works well and allows me to retrieve header elements like so:
if let metaInt = httpResponse.get("icy-metaint") {
self.icyMetaInt = Int(metaInt)
}
现在,我希望通过引入泛型函数使它更加优雅:
Now I wanted it to make a little bit more elegant by introducing a generic function:
func getHeader<T>(_ httpResponse: HTTPURLResponse, _ headerName: String) -> T? {
guard let element = httpResponse.get(headerName) else {
return nil
}
return T(element)
}
目的是使用这样的语句:
The intention is to use statements like this:
self.icyMetaInt = getHeader(httpResponse, "icy-metaint")
我相信类似的东西可以在C#左右运行.但是Swift编译器抱怨:
I believe something like that would work in C# or so. But the Swift compiler complains:
对于
return T(element)
即使我使用
return T.init(element)
有没有机会实现我的想法?
Is there any chance to achieve what I'm having in mind?
添加了T吗? (必须在编辑时丢失)
Added T? (must have been lost while editing)
推荐答案
之所以会发生这种情况,是因为编译器不知道应该调用哪个初始化器,因为您所做的事情太笼统了,因为出现了错误状态.您可以尝试实现什么目标,但是实现方式取决于您要实现的目标.
This happens because the compiler doesn't know which initializer it is supposed call, because what you are doing is simply too general, as the error states.What you are trying to achieve can be done, but the implementation depends on what you are achieve.
简而言之,如果您希望能够初始化很多不同的类型(原始或对象),则应定义一个新协议,扩展每种类型以实现您认为合适的此协议,并限制T类型遵守该协议.
In short, if you want to be able to initialize a lot of different types, be it primitives or objects, you should define a new protocol, extend each type to implement this protocol as you see fit and have the T Type restricted to this protocol.
protocol HTTPHeaderProtocol {
init(_ headerProtocolString: String?)
}
class MyCustomObject: HTTPHeaderProtocol {
var myString = ""
required init(_ headerProtocolString: String?) {
self.myString = headerProtocolString ?? ""
}
}
extension String: HTTPHeaderProtocol {
init(_ headerProtocolString: String?) {
self.init(headerProtocolString)
}
}
extension Int: HTTPHeaderProtocol {
init(_ headerProtocolString: String?) {
self.init(headerProtocolString)
}
}
extension HTTPURLResponse {
func get(_ header: String) -> String? {
let keyValues = allHeaderFields.map { (String(describing: $0.key).lowercased(), String(describing: $0.value)) }
if let headerValue = keyValues.filter({ $0.0 == header.lowercased() }).first {
return headerValue.1
}
return nil
}
func getHeader<T:HTTPHeaderProtocol>(_ httpResponse: HTTPURLResponse, _ headerName: String) -> T? {
guard let element = httpResponse.get(headerName) else {
return nil
}
return T(element)
}
}
这将起作用,希望能有所帮助:)
This will work, hope that helps:)
这篇关于Swift 4:“非标称类型'T'不支持显式初始化".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!