如何将 nil 作为可选的泛型函数参数传递



>我有一个函数如下:

func request<D: Decodable>(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
expecting type: D.Type? = nil,
completion: @escaping (Result<D?>) -> Void)

是否可以这样做:request(..., expecting: nil)还是func request<D: Decodable>(... expecting type: D.Type? = nil)

我想我已经达到了如何使用泛型的限制,因为当我这样做时,我会收到与我正在处理的代码完全无关的编译错误,所以我认为编译器可能会感到困惑。

当我使用该函数时,例如:request(from: "https:..", requestType: .post, body: body),编译器抱怨Enum element 'post' cannot be referenced as an instance member

我的一些 API 请求在正文中不返回任何内容,所以我正在尝试找到一种方法来表达我设置的这个通用函数

这里的根本问题是你想要的类型是 Void,但 Void 不是可解码的,并且你不能让它成为可解码的,因为非名义类型(如 Void(无法扩展。这只是 Swift 当前的一个限制。

正确的解决方案是过载。创建两种方法:

// For values
func request<D: Decodable>(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
expecting type: D.Type,
completion: @escaping (Result<D>) -> Void) {}
// For non-values
func request(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Error?) -> Void) {}

创建另一个共享方法,将请求转换为数据,并且两者都可以调用:

func requestData(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Result<Data>) -> Void) {}

您的解码请求函数现在会将.success(Data)转换为D。你的非解码请求函数将丢弃数据(或者如果你对它迂腐,可能会确保它是空的(,并调用完成处理程序。

如果您希望您的代码更加并行,以便它始终传递结果而不是错误?,那么您仍然可以通过调整签名来获得它:

func request(from urlString: String,
useToken: Bool = false,
requestType: RequestType = .get,
body: Data? = nil,
completion: @escaping (Result<Void>) -> Void) {}

但重载仍然是这里的答案。


(旧答案( 在这里传递nil没有问题,只要能以某种方式推断出D。但是必须有一种方法可以推断D。例如,以下内容应该没问题:

request(from: "") { (result: Result<Bool?>) in
print(result)
}

不好的是:

request(from: "") { (result) in
print(result)
}

因为在这种情况下,无法确定D是什么。

也就是说,鉴于您的目标,您无论如何都不希望Type是可选的。正如你所说,有时结果是"什么也不返回"。"不返回任何内容"的正确类型是Void,而不是 nil。

func request<D: Decodable>(from urlString: String,
useToken: Bool = false,
body: Data? = nil,
expecting type: D.Type = Void.self, // <<----
completion: @escaping (Result<D>) -> Void)

(我假设你想要Result<D>而不是Result<D?>,但根据您的确切用例,两者都可能是正确的。

Void是 Swift 中的正常类型。它是一个只有一个值的类型:(),空元组。

这对我来说在操场上很好

let t = testStruct.init()
let t2 : testStruct? = nil
test(t)
testOptional(t)
testOptional(t2)
func test<T: testProtocol>(_ para: T){
print(para.id())
}
func testOptional<T: testProtocol>(_ para: T?){
if let p = para{
print(p.id())
}
}
protocol testProtocol {
func id() -> String
}
struct testStruct{
}
extension testStruct : testProtocol {
func id() -> String {
return "hello"
} 
}

但你不能只调用 testOptional((。 它必须传递一些东西,甚至是 nil 可选,以便可以推断类型。

最新更新