Swift 4中类型与元类型的区别及动态类型数组创建问题
理清Swift中类型与元类型的区别,解决动态类型数组创建问题
先帮你点透核心问题:你混淆了类型本身和元类型实例的区别,这才导致了编译错误。
先搞懂类型 vs 元类型
- 类型(比如
A)是用来定义实例的“模板”,你可以用它声明变量:let a: A = A(),这里的A是编译期就能识别的类型标识符。 - 元类型(比如
A.Type)是描述类型本身的类型,A.self就是A.Type的一个实例——它代表A这个类型,但它本身是一个运行时的变量值,不是编译期的类型标识符。
你的代码里let otherType = A.self,otherType是一个存储了A.Type实例的变量,不是类型名称,所以[otherType]这种写法当然会报错“未声明的类型‘otherType’”——Swift要求数组的元素类型必须是编译期已知的类型,而不是一个变量。
解决方案分两种场景
场景1:类型在编译时可以确定
如果你的otherType对应的类型在编译时就能确定(比如你明确知道是A,只是想通过元类型的方式传递),可以用泛型来实现:
class A {} class B { // 定义泛型方法,接收元类型作为参数 func doStuff<T>(with targetType: T.Type) { // 这里直接用泛型参数T作为数组的元素类型 let itemArr: [T] = [A()] as! [T] // 如果你需要创建T的实例,可给T加初始化器约束,比如:where T: Initializable print("数组元素类型:\(type(of: itemArr[0]))") } } // 调用时传入元类型 let b = B() b.doStuff(with: A.self)
泛型是编译期处理的,所以Swift能确定T就是A,数组的类型[T]也就合法了。
场景2:类型完全由运行时动态决定
如果你的类型是运行时才确定的(比如根据用户输入、服务器返回的字符串来创建类型),Swift作为静态类型语言,无法直接创建编译期未知类型的数组。这时候可以用协议来保证类型安全(比用[Any]靠谱得多):
// 定义一个协议,让所有可能的类型都遵守它 protocol CommonType { // 定义所有需要共用的方法/属性 func commonMethod() } class A: CommonType { func commonMethod() { print("我是A类实例") } } class C: CommonType { func commonMethod() { print("我是C类实例") } } class B { func doStuff(with targetType: CommonType.Type) { // 数组的元素类型设为协议类型 var itemArr: [CommonType] = [] // 动态创建实例(需要确保类型有可访问的无参初始化器) if let instance = targetType.init() as? CommonType { itemArr.append(instance) } // 调用共用方法,类型安全 itemArr.first?.commonMethod() } } // 调用时可以传入任意遵守CommonType的类型 let b = B() b.doStuff(with: A.self) b.doStuff(with: C.self)
这样不管运行时传入什么类型,只要它遵守CommonType,就能安全地放到数组里并调用协议方法。
补充说明
如果非要坚持创建“动态类型的具体数组”,在Swift里是做不到类型安全的——因为静态类型系统要求数组的元素类型必须在编译期确定。这种情况下只能用[Any],但之后使用元素时需要强制类型转换,风险很高,不推荐。
内容的提问来源于stack exchange,提问作者mbamber
相关产品推荐
相关产品推荐

