我目前正在阅读Landmark应用教程,我在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引用和<T: Decodable>。有人能打破这个功能吗?谢谢。
发布于 2021-03-15 04:44:31
我看到这个问题在评论中得到了回答,但我觉得对于那些试图理解泛型的斯威夫特新手来说,这是值得的。
为了回答这个问题,让我们看看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的类型指定了type。这意味着参数type将保存类型T,而不是T类型的值。这是Swift在指定变量是类型的值与它的值是类型本身之间的区别。一开始,这可能有点令人困惑,但一旦你把注意力集中在泛型上,这就有意义了。
因为Swift是一种强类型语言,其中类型是在编译时定义的,所以decode需要知道它试图解码的东西的类型。在无类型语言(如JavaScript或Python )中,这是不必要的。在这些语言中,对象基本上是字典,所以它总是可以解码字典(或者数组,或者一小部分原语类型)。在Swift中,struct和class不仅仅是词典的语法糖。它们更像是C风格的struct --由类型决定的具有特定内存布局的二进制数据束。为了正确地解码,decode必须知道它正在解码什么,并且通常情况下,如何通过它的init(from: Decoder) throws方法(可能是编译器合成的)告诉它自己解码。是叫NSImage.init(from: Decoder)还是叫String.init(from: Decoder)等等..。?
如果您熟悉在OOP中实现运行时多态性的方式,那么提供这种类型,甚至是泛泛地提供一种获取类型的协议见证表的方法--这在某种程度上相当于类在运行时动态分派虚拟方法时所使用的"vtable“。所以让我们来做一些类似于在OOP中调用虚拟方法的事情,除非它通常可以在编译时计算出来,并且可以同时适用于值类型和引用类型。了解他的工作还可以了解不同但相关的问题,比如为什么在协议中直接声明的方法与仅在协议扩展中声明的方法有不同的多态行为(基本上协议中直接声明的方法在见证表中声明,因此可以动态分派,而仅在扩展中的方法不在见证表中,因此任何类型特定的实现都会丢失,而只能调用协议扩展中的实现)。
下面的函数使用它来打印其参数的类型(有更好的方法来实现这一点,但这说明了T.Type和T.self的角色):
func foo<T>(_ value: T)
{
let typeOfValue: T.Type = T.self
print("The value, \(value), is of type, \(typeOfValue).")
}https://stackoverflow.com/questions/66631340
复制相似问题