Swift5中的T.self是什么?

aor9mmx1  于 2023-02-28  发布在  Swift
关注(0)|答案(2)|浏览(192)

我现在正在浏览Landmarks应用程序教程,我正在学习如何将JSON加载到一个Struct中。
参考:https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

import Foundation

func load<T: Decodable>(_ filename: String) -> T {

    let data: Data

    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)

    else {

        fatalError("Couldn't find \(filename) in main bundle.")

    }

    do {

        data = try Data(contentsOf: file)

    } catch {

        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")

    }

    do {

        let decoder = JSONDecoder()

        return try decoder.decode(T.self, from: data)

    } catch {

        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")

    }

}

我特别不理解T.self引用,也不理解func开头的<T: Decodable>。有人能分解这个函数吗?谢谢。

rxztt3cl

rxztt3cl1#

  • 我看到这个问题在评论中得到了回答,但我觉得对于那些刚接触Swift并试图理解仿制药的人来说,这个问题值得一个实际的答案。*

为了回答这个问题,让我们看看T是什么,它在函数的签名中定义

func load<T: Decodable>(_ filename: String) -> T

这意味着泛型函数load(_:String) -> T返回某种符合Decodable的类型T,因此T是引用返回值类型的泛型方式,其中该类型将根据调用点的上下文确定,具体而言,根据接收返回值的任何对象的类型确定。
被问到的线路是

return try decoder.decode(T.self, from: data)

这里T.self是一种引用类型T本身的方式,如果你查看decode的函数签名,你会发现它看起来像这样:

func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T

注意,参数type的类型是T.Type,这意味着参数type将保存T类型,而不是T类型的值,这是Swift区分指定变量是一个类型的值与其值是类型本身的方法,这可能会让人有点困惑,但一旦你了解了泛型,它就有意义了。
因为Swift是一种强类型语言,类型是在编译时定义的,所以decode需要知道它试图解码的东西的类型。在JavaScript或Python这样的无类型语言中,这是不必要的。在这些语言中,对象基本上是字典,所以它总是可以解码字典(或数组,或一小组基本类型之一)。在Swift中,structclass不仅仅是字典的语法糖,它们更像是C风格的struct--一堆二进制数据,其特定的内存布局由类型决定。为了正确地解码,decode必须知道它正在解码什么,最常见的是,如何告诉它通过它的init(from: Decoder) throws方法(可能已经由编译器合成)来解码自己,它调用NSImage.init(from: Decoder)还是String.init(from: Decoder)等等?
如果你熟悉运行时多态在OOP中的实现方式,那么提供类型,即使是一般性的,也提供了一种获取类型的协议见证表的方法--这是类用于虚拟方法的运行时动态调度的“vtable”的协议等价物。所以让它做一些类似于在OOP中调用虚拟方法的事情。除了它通常可以在编译时计算出来之外,理解他的工作原理还可以让我们深入了解一些不同但相关的问题,比如为什么直接在协议中声明的必需方法的多态行为与仅在协议扩展中声明的方法不同(基本上,在协议中直接声明的那些在见证表中,因此它们可以被动态地分派,而仅在扩展中声明的那些不在见证表中,因此任何类型特定的实现都丢失了,取而代之的是,只有在协议的扩展中的实现可以被调用)。
下面的函数使用它来打印其参数的类型(有更好的方法来实现这一点,但这说明了T.TypeT.self的作用):

func foo<T>(_ value: T)
{
    let typeOfValue: T.Type = T.self
    print("The value, \(value), is of type, \(typeOfValue).")
}
bvhaajcl

bvhaajcl2#

import Foundation

var landMarks: [Landmark] = load("landmarkData.json")

func load<T: Decodable>(_ filename: String) -> T { 
...
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data) 
...
}

您缺少var landMarks: [Landmark] = load("landmarkData.json")这段代码,因为func load(_:)->T返回值类型是[Landmark]类型,所以T是[Landmark]数组类型。
这是我理解

相关问题