首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >T.self in Swift5是什么?

T.self in Swift5是什么?
EN

Stack Overflow用户
提问于 2021-03-15 01:40:28
回答 1查看 660关注 0票数 2

我目前正在阅读Landmark应用教程,我在JSON中加载到Struct的部分。它们给出了以下代码。

参考资料:https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

代码语言:javascript
复制
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引用和<T: Decodable>。有人能打破这个功能吗?谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-15 04:44:31

我看到这个问题在评论中得到了回答,但我觉得对于那些试图理解泛型的斯威夫特新手来说,这是值得的。

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

代码语言:javascript
复制
func load<T: Decodable>(_ filename: String) -> T

这意味着泛型函数load(_:String) -> T返回一些符合Decodable的类型T,因此T是引用返回值类型的一种通用方法,该类型将从调用站点的上下文中确定,特别是由接收返回值的内容的类型确定。

我们要问的是

代码语言:javascript
复制
return try decoder.decode(T.self, from: data)

这里,T.self是一种引用类型T本身的方法。如果您查看decode的函数签名,您会发现它如下所示:

代码语言:javascript
复制
func decode<T: Decodable>(_ type: T.Type, from data: Data) throws -> T

请注意,它为参数type的类型指定了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的角色):

代码语言:javascript
复制
func foo<T>(_ value: T)
{
    let typeOfValue: T.Type = T.self
    print("The value, \(value), is of type, \(typeOfValue).")
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66631340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档