初始数据结构点击“文件\新建\文件...”新建一个文件,并选择“IOS\Source\Swift File”。点击“下一步”并把这个文件命名为“OrderedDictionary”。最后,点击“创建”。 你会得到一个空的Swift文件,加这样一段代码进去:
到现在为止应该都没有什么问题。通过语义可以看出这个对象是一个结构体。 注意:总之,值的语义可以想象为“复制、粘贴的行为”,而不是“分享、参考的行为”。值的语义带来一系列的好处,例如不用担心一段代码无意地修改你的数据。了解更多,点击"Swift by Tutorials"的第三章节:类和结构体。 现在你需要将其一般化,以便它能够装载你需要的任何类型的数据。通过下列改变你对Swift中“结构”的定义:
在尖括弧中的元素是通用类型的参数。KeyType和ValueType不是他们自身的类型,而是你可以使用在结构里定义取代的类型。现在就简洁清新许多了! 最简单的实现一个有顺序的字典是保持一个数组和一个字典。字典中将会装载衍射,而数组将装载keys的顺序。 在结构体内部的定义中,加入以下的代码:
这样声明有两个目的,就像上例描述的,有两种类型的用于给已经存在的类型的取新的名称的别名。在这,你将分别地为后面的数组和字典赋值了别名。声明别名是将复杂类型定义为更短名称的类型的一种非常有效的方式。 你将注意怎么样从结构体中定义用“KeyType”和“ValueType”的参数类型中替换类型。上例的"KeyTypes"是数组类型的。当然这是没有这样的类型的“KeyType”;当在一般的实例化时,将替代Swift像对OrderedDictionary的类型的一切类型通过。 就因为这样,你将会注意到编译错误:
或许你会诧异怎么会这样?请再观察下Dictionary的继承者:
除了在KeyType之后的HashTable, 其他的都和OrderedDictionary的定义特别的相似。在分号后面为KeyType声明的Hashable,一定符合Hashable的协议。这是因为字典需要为hash key实现。 用这种方式约束泛型参数是非常常见的。例如,你想要依据你的应用使用参数做什么,来约束值的类型以,确保相等性、可打印性协议。 打开OrderedDictionary.Swift,用下例来取代你对结构体的定义:
这样为OrderedDictionary声明KeyType,必须符合Hashable。这就意味着,无论KeyType变成什么类型,都可以接受为没有声明的字典的KEY。 这样,文件再次编译,将不会报错! Keys, Values 和所有的这些趣事如果不能为字典添加值,那么字典有什么作用了?打开OrderedDictionary.swift,在你的结构体定义中添加以下函数:
下面介绍一些新的特性。让我们一步一步来介绍:
现在你可以为字典添加移除值? 像下列对OrderedDictionary结构体的定义的函数:
现在再让我们一步一步分析: 1.这是改变结构体状态的函数,removeAtIndex的名称需要和数组的方法匹配。恰当的时候,考虑使用镜像系统库中API是不错的选择。这样帮助开发者在他们的工作平台里,非常容易地使用你的API。 2.首先,你需要检查索引,观察他们是否是在大量的数组里。尝试着从未声明的数组中移除越位的元素,将会导致超时错误,所有在这时检查将会更早符合这样的情况。你或许在Objective-C中使用断言函数;在Swift中断言也是可使用的。但是前提是在释放的工程中是活动的,否则你运行的应用的将会终止。 3.接着,当同时从数组中移除值时,你在给定的索引中数组中获得值。 4.然后,你从字典中为这个key移除的值,同时也会返回这个值。或许在给出的key中,字典也没有相应的值,所以removeValueForKey返回一个可选的。这种情况下,你知道字典将会为给出的key,包含一个值,因为这是唯一的自己给字典添加值的方法--insert(_:forKey:atIndex:),这时你可以选择使用“!”,表明这将会有正义感值。 5.最后,你在一个元组返回的key和value。数组的removeAtIndex和字典的removeValueForKey是一样的返回已存在的值功能。 值的读取跟写入把值写入字典(dictionary)是没问题了, 可是这样还不够! 你还需要实现一个方法(method) 从字典中读出相应的值. 打开 OrderedDictionary.swift 文件, 然后把下列代码添加到结构定义(struct definition)当中, , 就放在 thearrayanddictionaryvariable 声明的下面:
这个常用的属性, 用来算出字典里面有几条记录. 只要返回数组的 count 属性的中值就可以了! 接下来, 就是如何访问(Access)字典中的记录了(Element). 我们可以通过下标(Subscript)来访问, 代码如下:
下标的语法我们会用了, 但是如果是我们自己定义的类那该怎么用呢? 好在 Swift 支持在自定义类里头添加这项功能. 而且实现起来也不复杂. 把下列代码添加到结构定义的底部:
我们详细解释下这段代码:
就像用 Swift 自带的字典类的下标那样去, 你可以通过 key 来查找某个值. 可是如果我们需要像访问数组那样, 用下标索引(index)访问某个值, 该怎么办呢? 既然是有序字典, 没有道理不能通过下标索引一个一个的按顺序访问. 结构体跟类可以定义多个参数类型不同的下标(subscript). 把下列代码添加到结构定义的底部:
这段代码跟前面那段类似, 不同的是参数类型变成了 Int. 因为我们现在要实的功能是现像数组那样, 使用下标索引访问有序字典. 不过这次返回的是由 key 跟 value 组成的一个元组(tuple). 因为有序字典就是由这样一个一个的元组构成的. 下面具体解释下这段代码:
挑战: 为上面那个下标实现 setter . 可以参考前面的例子.
也许你会好奇, 如果 KeyType 是 Int 型的, 会出现什么问题? 使用泛型的好处是, 不管是什么类型, 只要能算出哈希值(hashable)的就行, 所以 Int 当然也能用. 问题是, 当 key 也是 Int 型的时候, 这俩个下标该怎么区分呢? 这就需要我们给编译器提供更多的类型信息. 让它知道在什么时调用哪个下标. 比如我们定义的这两个下标, 返回的类型不一样. 如果你用 key-value 类型的元组给它赋值, 编译器就会自动调用那个数组式(array-style )的下标. |