Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift5中的T.self是什么?_Swift - Fatal编程技术网

Swift5中的T.self是什么?

Swift5中的T.self是什么?,swift,Swift,我目前正在学习Landmarks应用程序教程,我正在学习将JSON加载到结构中的部分。他们给出了以下代码 参考: 导入基础 func load(u文件名:String)->T{ 让数据:数据 guard let file=Bundle.main.url(forResource:filename,扩展名:nil) 否则{ fatalError(“在主捆绑包中找不到\(文件名)。” } 做{ 数据=尝试数据(contentsOf:file) }抓住{ fatalError(“无法从主捆绑包加载\(文

我目前正在学习Landmarks应用程序教程,我正在学习将JSON加载到结构中的部分。他们给出了以下代码

参考:

<代码>导入基础 func load(u文件名:String)->T{ 让数据:数据 guard let file=Bundle.main.url(forResource:filename,扩展名:nil) 否则{ fatalError(“在主捆绑包中找不到\(文件名)。” } 做{ 数据=尝试数据(contentsOf:file) }抓住{ fatalError(“无法从主捆绑包加载\(文件名):\n\(错误)”) } 做{ let decoder=JSONDecoder() 返回try decoder.decode(T.self,from:data) }抓住{ fatalError(“无法将\(文件名)解析为\(t.self):\n\(错误)”) } } 我特别不理解函数开头的
t.self
参考和
。有人能把这个功能分解掉吗?谢谢。

我看到这个问题在评论中得到了回答,但我觉得对于那些刚刚接触Swift试图理解泛型的人来说,这是一个值得实际回答的问题

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

func加载(\ufilename:String)->T
这意味着泛型函数
load(quo:String)->T
返回符合
Decodable
的某种类型
T
,因此
T
是引用返回值类型的泛型方法,其中该类型将根据调用站点的上下文确定,具体来说,根据接收返回值的对象的类型

正在询问的线路是

返回尝试解码器。解码(T.self,from:data)
这里的
T.self
是指类型
T
本身的一种方式。如果您查看
decode
的函数签名,您会发现它看起来像这样:

func解码(utype:T.type,from data:data)抛出->T
注意,对于参数的类型,
Type
,它表示
T.Type
。这意味着参数
type
将保存类型
T
,而不是类型
T
的值。这是斯威夫特区分指定变量为类型值与指定变量值为类型本身的方法。一开始这可能有点让人困惑,但一旦你了解了泛型,这是有意义的

因为Swift是一种强类型语言,类型是在编译时定义的,
decode
需要知道它试图解码的对象的类型。在无类型语言(如JavaScript或Python)中,这是不必要的。在这些语言中,对象基本上是字典,因此它总是可以解码字典(或数组,或一小组基本类型之一)。在Swift中,
struct
class
不仅仅是字典的语法糖。它们更像是C-style
struct
——一组二进制数据,具有由类型决定的特定内存布局。为了正确地解码,
decode
必须知道它在解码什么,而且最常见的情况是,如何通过它的
init(from:Decoder)抛出
方法(可能是由编译器合成的)告诉它自己解码。它是调用
NSImage.init(从:解码器)
,还是调用
String.init(从:解码器)
,等等

如果您熟悉在OOP中实现运行时多态性的方式,那么提供类型(即使是一般性的)提供了一种获取类型的协议见证表的方法,该表在某种程度上相当于类用于虚拟方法的运行时动态调度的“vtable”。所以我们让它做一些类似于在OOP中调用虚方法的事情,只是它通常可以在编译时找到它,并且它可以用于值类型和引用类型。了解他的工作方式也可以深入了解不同但相关的问题,比如为什么直接在协议中声明的所需方法与仅在协议扩展中声明的方法具有不同的多态行为(基本上,协议中直接声明的实现在见证表中,因此可以动态调度它们,而只有扩展中的实现不在见证表中,因此任何特定于类型的实现都将丢失,而只能调用协议扩展中的实现)

以下函数使用它来打印其参数的类型(有更好的方法,但这说明了
T.type
T.self
的作用):

func foo(u值:T)
{
让typeOfValue:T.Type=T.self
打印(“值\(value)的类型为\(typeOfValue)。”
}

你知道
String.self
Int.self
SomeType.self
是什么意思吗?我知道
self
指的是问题中的对象本身,但我不是完全清楚不。
String.self
指的是字符串本身,类型。啊,好吧,谢谢你的详细回答。:]!
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)")

    }

}