Swift 3.2中泛型函数与协议的类型推断失败问题咨询
聊聊Swift泛型函数调用的那些坑
先把背景代码摆出来,方便大家理解:
// 泛型函数,返回遵循JSONDecodable协议的类型数组 func doSomething<T: JSONDecodable>() -> [T] { return [] } // 定义协议 protocol JSONDecodable {} // 遵循协议的具体类型 struct Animal: JSONDecodable {}
现在咱们的需求是:不手动指定Animal作为泛型参数,调用doSomething()。这里几种写法的结果完全不同,咱们来唠唠:
能跑通的写法
直接给变量加具体类型的注解,让编译器自己猜泛型参数:
let result: [Animal] = doSomething()
这招好使的原因很简单——编译器看到result需要是[Animal],就能反向推断出泛型T就是Animal,自动帮你把泛型函数的类型填上,完美运行。
跑不通的写法
要是你想直接用协议类型当数组注解,就会踩坑:
let result: [JSONDecodable] = doSomething() // 编译报错:无法将类型'_'转换为预期类型'[JSONDecodable]'
为啥不行?因为doSomething()返回的是某一个具体类型的数组(比如[Animal]),而[JSONDecodable]是一堆遵循协议的任意类型的集合(存在类型数组),这俩在Swift里根本不是一回事儿。泛型函数必须要一个明确的具体类型来填充T,但JSONDecodable作为协议本身没法直接当泛型参数用,编译器根本不知道该生成哪个版本的doSomething(),自然就报错了。
存类型再用的坑
要是你想先把类型存起来再用,也会翻车:
let savedType = Animal.Type let result: [savedType] = doSomething() // 编译错误
这里的问题是,savedType是个变量,但类型注解需要的是一个实实在在的类型,不是变量。真要想这么玩,得用typealias定义类型别名:
typealias SavedType = Animal let result: [SavedType] = doSomething()
本质上还是得让编译器明确知道T的具体类型,不然泛型函数根本没法工作。
内容的提问来源于stack exchange,提问作者Mishka
相关产品推荐
相关产品推荐

