swift - Swift P.Protocol vs P.Type
问题描述
以下似乎有效:
protocol P {}
class C: P {}
let c = C()
func foo<T>(_ t: T.Type) -> T? { return c as? T }
let p = foo(P.self)
print(type(of: p)) // Optional<P>
但是,究竟如何?
- 如果类型
p
是P?
,那意味着T === P
infoo()
,对吗? - 这意味着
t
参数的类型foo()
是P.Type
。 - 的类型
P.self
是P.Protocol
。 - 所以我们传递一个
P.Protocol
tofoo()
,它被转换为P.Type
。 - 但是为什么这样的转换不会失败呢?据记载,协议不符合自身。
- 事实上,做事
let pt: P.Type = P.self
确实失败了。 P.Protocol -> P.Type
失败的直接转换和调用时发生的隐式转换有什么区别foo(P.self)
?
解决方案
P.Protocol
是协议的元类型P
,就像T.Type
是非协议类型的元类型T
。没有进行“转换”。
那么是什么P.Type
呢?
P.Type
是一种存在的元类型。非协议类型没有对应的东西。假设您要存储符合 的具体类型的元类型P
,您可以将其存储在P.Type
:
let x: P.Type = C.self
注意P.Type
只能存储具体类型的元类型,并且P.Protocol
只能存储协议的元类型。要了解为什么这种划分很重要,假设P
定义了静态方法foo
,然后您可以调用x.foo()
. 这可以保证工作,因为P.Type
必须有一个具体的类型,它将实现foo
. 另一方面,您不能调用foo
on ,因为inP.Protocol
没有实现。foo
P
另见:https ://swiftrocks.com/whats-type-and-self-swift-metatypes
推荐阅读
- c# - 每次单击按钮时自定义错误“on”抛出错误
- ios - 如何在 UITableView [Swift] 中设置特定的节标题
- ruby-on-rails - 如何在本地工作的 Rails 项目中从 SQLite 数据库更改为 PostgreSQL 数据库?
- java - 在生产中使用spring boot有什么缺点?
- extjs6 - 卡片布局问题
- php - 如何从日期生成唯一订单号并将其插入数据库?
- c++ - 从 cpp 执行选择查询时,DB 在什么情况下不会关闭游标?
- java - 我如何将语音替换为每个编辑文本
- angular - 如何在角度单元测试期间修复未定义的“无法读取属性订阅”?
- c# - 从 Godaddy 托管的网站发送电子邮件时出错