如何在泛型函数中使用 swift 泛型 Decodable 协议

How do I use swift generic Decodable protocol in generic functions

我想编写一个通用函数来解析结果并 return 在成功的闭包块中或在失败块中发回错误。

我收到这样的错误'无法推断通用参数 'T''

这是我的示例代码。

let jsonString = """
{
"id": 1,
"msg": "Sample msg"
}
"""

struct Post: Codable {
    var id: String?
    var msg: String?
}

enum PostError: Error {
    case empty
}


func fetch<T:Decodable>(_ completion: @escaping (Result<T?, PostError>) -> Void)  {

        do {
            let data = Data(jsonString.utf8)
            let post = try JSONDecoder().decode(T.self, from: data)
            completion(.success(post))
        }
        catch {
            completion(.failure(.empty))
        }
    }


fetch { res in
        switch res {
        case .success( let p):
            print(p.description)

        case .failure(let error):
            print(error)
        }
    }

这是我遇到的错误。

您可以接受泛型类型作为参数,如下所示:

func fetchObject<T:Decodable>(ofType type: T.Type, _ completion: @escaping (Result<T, PostError>) -> Void)  {
   do {
      let data = Data(jsonString.utf8)
      let post = try JSONDecoder().decode(type, from: data)
      completion(.success(post))
   }
   catch {
      completion(.failure(.empty))
   }
}

用法:

fetchObject(ofType: Post.self) { res in
   switch res {
       case .success(let post):
          print(post.description)
       case .failure(let error):
          print(error)
   }
}

我明白你想做什么,但主要问题是你从来没有指定类型。编译器知道您要调用 fetch 但它不知道您要获取什么或将其解析为什么。

如果你看一下你的 fetch 调用,你会发现编译器没有任何地方可以告诉你你正在尝试做什么或你期望发生什么。

您要么必须:

1。将类型作为参数传递

func fetch<T: Decodable>(_ type: T.Type, _ completion: @escaping (Result<T, PostError>) -> Void)  {

    do {
        let data = Data(jsonString.utf8)
        let post = try JSONDecoder().decode(T.self, from: data)
        completion(.success(post))
    }
    catch {
        completion(.failure(.empty))
    }
}


fetch(Post.self) { res in
        switch res {
        case .success(let p):
            print(p)

        case .failure(let error):
            print(error)
        }
    }

或...

2。在函数所属的对象实例化时指定类型:

struct Fetcher<T: Decodable> {

    func fetch(_ completion: @escaping (Result<T, PostError>) -> Void)  {

        do {
            let data = Data(jsonString.utf8)
            let post = try JSONDecoder().decode(T.self, from: data)
            completion(.success(post))
        }
        catch {
            completion(.failure(.empty))
        }
    }
}

let fetcher = Fetcher<Post>()
fetcher.fetch { res in
    switch res {
    case .success(let p):
        print(p)

    case .failure(let error):
        print(error)
    }
}