Swift中Stack遵循ExpressibleByArrayLiteral的init写法为何与Apple文档不同?
别担心,这两种写法都是完全合规的,只是各自适配了结构体的内部逻辑而已!咱们一步步拆解清楚:
协议的核心要求
ExpressibleByArrayLiteral协议只有一个硬性规定:你必须实现一个名为init(arrayLiteral:)的初始化方法,参数是可变参数类型Element...。不管是书中的Stack实现,还是Apple文档里的OrderedSet实现,都满足这个核心要求——这也是它们都能通过数组字面量初始化的原因。
两种实现的差异细节
书中Stack的简洁实现
先看你的Stack代码:
public struct Stack<Element> { private var storage: [Element] = [] public init(_ elements: [Element]) { storage = elements } } extension Stack: ExpressibleByArrayLiteral { public init(arrayLiteral elements: Element...) { storage = elements } }
这里的关键是:Stack的内部存储storage本身就是一个普通的[Element]数组,而协议要求的arrayLiteral参数(可变参数Element...)在方法内部会自动转换成[Element]类型。所以直接把elements赋值给storage是最直接高效的写法,完全不需要额外逻辑。
甚至你还可以复用Stack已有的初始化方法,把扩展里的代码改得更简洁:
public init(arrayLiteral elements: Element...) { self.init(elements) }
效果和原代码完全一致,只是更复用了已有的逻辑。
Apple文档里OrderedSet的特殊实现
再看文档里的示例:
extension OrderedSet: ExpressibleByArrayLiteral { init(arrayLiteral: Element...) { self.init() for element in arrayLiteral { self.append(element) } } }
这是因为OrderedSet是一个有序且不允许重复元素的集合,它的内部存储逻辑和普通数组不一样:直接把数组赋值进去会跳过它的去重、顺序维护逻辑。所以必须通过逐个调用append方法,让OrderedSet自己处理每个元素的添加过程(比如检查元素是否已存在、维护有序结构)。
总结一下
两种写法没有对错之分,只是根据结构体的内部实现逻辑选择了最适合的方式:
- 如果你的结构体内部就是普通数组存储,直接赋值是最简洁高效的;
- 如果你的结构体有特殊的元素处理规则(比如去重、自定义排序、状态校验),就需要逐个处理元素,调用自己的添加逻辑。
你能成功用var stack: Stack = [1.0, 2.0, 3.0, 4.0]初始化栈,就说明两种实现都是完全符合协议要求的~
内容的提问来源于stack exchange,提问作者Marcus Kim

