【发布时间】:2017-11-17 10:35:16
【问题描述】:
我正在使用这个扩展来检索 urlSession 回调中的 HTTP 标头:
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
}
}
这很好用,让我可以像这样检索标题元素:
if let metaInt = httpResponse.get("icy-metaint") {
self.icyMetaInt = Int(metaInt)
}
现在我希望通过引入一个泛型函数使它更优雅一点:
func getHeader<T>(_ httpResponse: HTTPURLResponse, _ headerName: String) -> T? {
guard let element = httpResponse.get(headerName) else {
return nil
}
return T(element)
}
目的是使用这样的语句:
self.icyMetaInt = getHeader(httpResponse, "icy-metaint")
我相信类似的东西可以在 C# 中使用。但是 Swift 编译器抱怨:
非标称类型 'T' 不支持显式初始化
为
return T(element)
即使我使用
return T.init(element)
有没有机会实现我的想法?
编辑:添加了 T? (一定是在编辑时丢失了)
【问题讨论】:
-
泛型不是这样工作的。即使他们这样做了,你也没有告诉编译器
T是什么。 -
另外,您正试图从一个不返回可选项的函数返回
nil -
是的,你是对的。需要加T吗?但是,这是泛型函数在 C# 中运行良好的方式。问题是,编译器知道 T,因为赋值 self.icyMetaInt(它是 Int?)说明了一切。我看不出有什么理由,为什么那不应该起作用。但如果它在 Swift 中不起作用,那么它就不起作用。没问题
-
问题是:Swift 允许我像这样创建两个函数: func getHeader(_ httpResponse: HTTPURLResponse, _ headerName: String) -> String? { guard let element = httpResponse.get(headerName) else { return nil } return String(element) } func getHeader(_ httpResponse: HTTPURLResponse, _ headerName: String) -> Int? { guard let element = httpResponse.get(headerName) else { return nil } return Int(element) } “通用”解决方案会更好......
-
泛型不是由返回上下文决定的。它由对象实例确定,因此您需要一个
HTTPURLResponse<Int>的实例,以便编译器知道 T 是一个 Int,然后您不能将另一个标头值解释为字符串,而且它也因为您无法控制响应对象的实例化,所以无法正常工作。