Swift 中泛型的使用

对于类型安全(type-safe)语言,一个常见的问题就是如何编写适用于多种类型输入的程序。想象一下,两个整型数相加和两个浮点数相加的程序看起来应该非常类似,甚至一模一样才对。唯一的区别就是变量的类型不同。

在强类型语言中,你需要去定义诸如addInts, addFloats, addDoubles 等方法来正确地处理参数及返回值。

许多编程语言已经解决了这个问题。例如,在C++中,使用Template来解决。而Swift,Java和C#则采用了泛型来解决这个问题。

下面用有序字典(Ordered Dictionaries)来简单说明一下泛型的用法:

和数组不同的是,包括Swift在内地很多编程语言和框架都不保证集合(sets)和字典(dictionaries)的数据存储顺序。有序字典和普通的字典类似,不同之处在于它的key是有序的。

创建有序字典

点击“文件\新建\文件…”新建一个文件,并选择“IOS\Source\Swift File”。点击“下一步”并把这个文件命名为“OrderedDictionary”。最后,点击“创建”。

你会得到一个空的Swift文件,加这样一段代码进去:

struct OrderedDictionary {
}

到现在为止应该都没有什么问题。通过语义可以看出这个对象是一个结构体。

现在你需要将其一般化,以便它能够装载你需要的任何类型的数据。通过下列改变你对Swift中“结构”的定义:

struct OrderedDictionary<KeyType, ValueType>

在尖括弧中的元素是通用类型的参数。KeyType和ValueType不是他们自身的类型,而是你可以使用在结构里定义取代的类型。现在就简洁清新许多了!

最简单的实现一个有顺序的字典是保持一个数组和一个字典。字典中将会装载衍射,而数组将装载keys的顺序。

在结构体内部的定义中,加入以下的代码:

typealias ArrayType = [KeyType]
typealias DictionaryType = [KeyType: ValueType]
var array = ArrayType()
var dictionary = DictionaryType()

这样声明有两个目的,就像上例描述的,有两种类型的用于给已经存在的类型的取新的名称的别名。在这,你将分别地为后面的数组和字典赋值了别名。声明别名是将复杂类型定义为更短名称的类型的一种非常有效的方式。

你将注意怎么样从结构体中定义用“KeyType”和“ValueType”的参数类型中替换类型。上例的”KeyTypes”是数组类型的。当然这是没有这样的类型的“KeyType”;当在一般的实例化时,将替代Swift像对OrderedDictionary的类型的一切类型通过。

就因为这样,你将会注意到编译错误:

Type 'Keytype' does not conform to protocol 'Hashable'

这是因为你的字典Key没有遵循Hashable协议; 我们可以手动修改代码让Key遵循Hashable协议:

struct OrderedDictionary<KeyType: Hashable, ValueType

接下来我们就需要正式建立有序字典了;

  • 添加count属性
var count: Int {
return self.array.count
}
  • 添加插入和移除方法
mutating func removeAtIndex(index: Int) -> (KeyType, ValueType) {
precondition(index < self.array.count, "Index 超出范围")
assert(index < self.array.count)
let key = self.array.removeAtIndex(index)
let value = self.dictionary.removeValueForKey(key)!
return (key, value)
}
mutating func insert(value: ValueType, forKey key: KeyType, atIndex index:Int) -> ValueType? {
var adjustedIndex = index
let existingValue = self.dictionary[key]
if existingValue != nil {
let existingIndex = self.array.indexOf(key)
if existingIndex < index {
adjustedIndex--
}
self.array.removeAtIndex(existingIndex!)
}
self.array.insert(key, atIndex: adjustedIndex)
self.dictionary[key] = value
return existingValue
}

注意在结构体内如果方法需要修改结构体内的属性的话,要在方法前加mutating关键字;

  • 添加下标访问方法:
subscript(key: KeyType) -> ValueType? {
get {
return self.dictionary[key]
}
set {
if let _ = self.array.indexOf(key) {}else {
self.array.append(key)
}
self.dictionary[key] = newValue
}
}
subscript(index: Int) ->(KeyType, ValueType) {
get {
precondition(index < self.array.count, "Index 超出范围")
let key = self.array[index]
let value = self.dictionary[key]!
return (key, value)
}
}

这样我们就利用泛型创建了一个有序字典。