我有一些对象当前是通过采用数组或字典的单参数
init
函数初始化的。
我意识到我可以使用
ExpressibleByArrayLiteral
和 ExpressibleByDictionaryLiteral
来代替。但我相信我仍然需要非文字初始化器,也许直到实现在 Swift 中将数组传递给具有可变数量参数的函数。
struct ArrayStruct: ExpressibleByArrayLiteral {
typealias ArrayLiteralElement = Int
let array: [Int]
init(array: [Int]) {
self.array = array
}
init(arrayLiteral elements: Int...) {
self.init(array: elements) // ok
}
}
struct DictStruct: ExpressibleByDictionaryLiteral {
typealias Key = String
typealias Value = Int
let dict: [String : Int]
init(dict: [String : Int]) {
self.dict = dict
}
init(dictionaryLiteral elements: (String, Int)...) {
self.init(dict: elements) // Cannot convert value of type '(String, Int)...' to expected argument type '[String : Int]'
}
}
我希望初始化程序都调用相同的代码路径,因此变量 init 可以调用集合 init,反之亦然。
对于数组,我可以将
Int...
可变参数直接传递给现有的 [Int]
初始值设定项。为什么这只适用于数组?
但这对词典不起作用。现有的初始化程序需要一个
[String : Int]
字典,但 ExpressibleByDictionaryLiteral
函数参数是 (String, Int)...
为什么这些“可通过数组/字典文字表达”首先给你一个可变参数,而不是数组/字典?这是一个文字数组...为什么它不给你一个数组?
如何将
(String, Int)...
转换为 [String : Int]
?
问题在于,从键值对列表到字典没有“明显”的转换。您必须决定如何处理重复项。它们是否是编程错误导致崩溃?你拿第一个吗?最后一个?以某种方式将它们结合起来?由您决定,Swift 支持所有这些方法。
例如,如果键不唯一(这对于文字来说不是一个坏主意),要使程序崩溃,您可以这样写:
init(dictionaryLiteral elements: (String, Int)...) {
let dict = Dictionary(uniqueKeysWithValues: elements)
self.init(dict: dict)
}
或者,要获取给定键的最后一个元素,您可以这样写:
init(dictionaryLiteral elements: (String, Int)...) {
let dict = Dictionary(elements, uniquingKeysWith: { _, second in second })
self.init(dict: dict)
}