Swift泛型类型指定场景及类与结构体泛型差异咨询
Swift泛型:什么时候要指定占位符类型,什么时候不用?
咱们先把第一个问题拆解明白——在Swift里,泛型占位符的类型指定规则其实挺有规律的,分两种情况来看:
需要指定泛型类型的场景
- 直接实例化泛型类型,但上下文没法推断:比如你要创建一个Node实例,如果是无参数可用于推断的初始化方法,必须明确写
Node<Int>(value: 5);要是只定义变量但暂不赋值,比如var myNode: Node也会报错,得写成var myNode: Node<Int>。 - 调用泛型函数,但编译器无法从参数/返回值推断类型:比如有个泛型函数
func createEmptyContainer<T>() -> Container<T>,调用时必须指定T,写成createEmptyContainer<String>(),不然编译器不知道你要什么类型的容器。 - 在泛型类型外部引用该类型,但没有上下文推断:比如在非泛型类里定义
var node: Node,必须加<Int>这类具体类型,不然编译器找不到北。
无需指定泛型类型的场景
- 在泛型类型内部引用自身:这就是你代码里的核心原因!在泛型类/结构体/枚举的定义内部,直接写类型名(比如
Node),编译器会自动把它解析成当前泛型类型的具体实例,也就是Node<T>(这里的T就是类定义里的占位符)。所以var leftChild: Node?其实等价于var leftChild: Node<T>?,完全合法。 - 上下文能明确推断出类型:比如
let node = Node(value: 5),因为传入的value是Int,编译器自动知道T是Int,不用额外指定;再比如把一个Node<Int>赋值给var anotherNode: Node?,编译器也能从赋值内容推断出类型。 - 泛型函数的参数/返回值能推断类型:比如经典的
swap(_:_:)函数,调用swap(&x, &y)时,只要x和y类型一致,编译器就知道T是什么,根本不用你写swap<Int>(&x, &y)。
再来说你第二个问题里的Node类代码:
class Node<T: Comparable>{ var leftChild: Node? // 为何无错误?! var rightChild: Node? // 为何无错误?! var value: T init(value: T){ self.value = value } func addleft(node: Node){ leftChild = node } func addright(node: Node){ rightChild = node } }
刚才已经提到了,Swift对泛型类型内部的自身引用有语法糖支持——在类内部写Node就等同于Node<T>,所以不管是属性还是方法参数,这么写都是合法的,编译器会自动补全泛型参数。
那你说的结构体不指定会报错,应该是在结构体外部使用的时候没给泛型类型吧?比如你定义一个泛型结构体:
struct LinkedList<T> { var next: LinkedList? // 内部这么写完全没问题! var value: T }
在结构体内部写LinkedList?是完全OK的,和类一样。但如果你在外部写var list: LinkedList,这就会报错,因为编译器不知道T具体是什么,必须写成var list: LinkedList<String>或者通过初始化推断let list = LinkedList(value: "hello")。
另外提个小细节:你代码里的addleft和addright方法,参数node: Node其实只能接受和当前Node同类型的实例(比如当前是Node<Int>,就只能传Node<Int>)。如果想让方法接受任意类型的Node,那得把方法也改成泛型的,不过这就是另一个话题啦~
内容的提问来源于stack exchange,提问作者mfaani
相关产品推荐
相关产品推荐

