通用方法中T和Self之间的区别

时间:2019-03-29 09:03:28

标签: swift generics protocols swift-protocols

我正在编写一个名为JSONDataInitializable的协议,它将使用Data从包含JSON的JSONDecoder初始化值。

it’s not possible在初始化程序中显式使用泛型以来,我在协议扩展中声明了一种与类型无关的通用辅助方法,初始化程序随后调用该方法。

但是,我想出了一种写这种方法的方法,而不是两种。

(1):

private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
    return try JSONDecoder().decode(T.self, from: jsonData)
}

(2):

private static func initialize(from jsonData: Data) throws -> Self {
    return try JSONDecoder().decode(Self.self, from: jsonData)
}

您能解释一下这两种方法之间的区别吗?他们似乎都产生了相同的结果。

唯一可见的区别是第一个变体中的协议一致性部分。但是,这些方法是在协议扩展中声明的,因此仅适用于符合协议的类型。

UPD

这是完整的协议声明:

protocol JSONDataInitializable: Decodable {
    init?(from jsonData: Data)
}

extension JSONDataInitializable {

    init?(from jsonData: Data) {
        do {
            self = try Self.initialize(from: jsonData)
        } catch {
            print(error)
            return nil
        }
    }

    // (1)
    private static func initialize<T: JSONDataInitializable>(from jsonData: Data) throws -> T {
        return try JSONDecoder().decode(T.self, from: jsonData)
    }

    // ⬆⬆⬆
    // OR
    // ⬇⬇⬇

    // (2)
    private static func initialize(from jsonData: Data) throws -> Self {
        return try JSONDecoder().decode(Self.self, from: jsonData)
    }

}

假设我们有一个名为User的结构Decodable。我们需要从JSON(存储为User)中初始化Data的值。使用该协议,初始化的工作方式如下:

// Protocol conformance declaration
extension User: JSONDataInitializable { }

// JSON stored as Data
let networkData = ...

// Initialization
let john = User(from: networkData)

1 个答案:

答案 0 :(得分:1)

使用_prepare_x._asarray_validated的第二种实现符合您的要求。您要在协议中创建一个初始化器,可以在要初始化的类型上调用它。协议功能中的Self指的是您在其上调用特定方法的类型。

另一方面,泛型实现将允许您初始化符合协议的任何类型,但是在您的Self方法中,您将返回值分配给init(from:),因此泛型类型参数{ {1}}将被推断为self。这使得不必使方法通用,因为在特定类型上,T将始终为Self