从Swift3的标准库协议看面向协议编程(一)
Swift中,大量内置类如Dictionary,Array,Range,String都使用了协议
先看看Hashable
哈希表是一种基础的数据结构.,Swift中字典具有以下特点:字典由两种范型类型组成,其中 key 必须实现 Hashable 协议.关于 swift 中字典是怎么实现的,可以看这篇 .
- public protocol Hashable : Equatable {
- public var hashValue: Int { get }
- }
可以看到 Hashable遵循了 Equable,那再来看看 Equable
- public protocol Equatable {
- public func ==(lhs: Self, rhs: Self) -> Bool
- }
看来遵循 Equable 都必须重载这个 == ,来定义自己的判等方法.
上 sample:
- struct MyPoint: Hashable, Comparable {
- var x: Int
- var y: Int
- var hashValue: Int {
- get {
- return x.hashValue + y.hashValue
- }
- }
- }
- func ==(lhs: MyPoint, rhs: MyPoint) -> Bool {
- return lhs.hashValue == rhs.hashValue
- }
- let pointA = MyPoint(x: , y: )
- let pointB = MyPoint(x: , y: )
- let pointC = MyPoint(x: , y: )
- pointA == pointB //true
- pointA == pointC //false
如果需要比较大小需要遵循 Comparable这个协议,协议需要内容就不贴了,直接上 code:
- func <(lhs: MyPoint, rhs: MyPoint) -> Bool {
- return lhs.hashValue < rhs.hashValue
- }
- func <=(lhs: MyPoint, rhs: MyPoint) -> Bool {
- return lhs.hashValue <= rhs.hashValue
- }
- func >(lhs: MyPoint, rhs: MyPoint) -> Bool {
- return lhs.hashValue > rhs.hashValue
- }
- func >=(lhs: MyPoint, rhs: MyPoint) -> Bool {
- return lhs.hashValue >= rhs.hashValue
- }
- pointA >= pointB //true
- pointA > pointC //false
- pointA < pointC //true
借用 Mattt的话来做下总结:
在 Swift 中,Equatable 是一个基本类型,由此也演变出了 Comparable 和 Hashable 两种类型。这三个一起组成了这门语言关于对象比较的核心元素。
再看看Sequence (这部分 Swift3有变化)
SequenceType(Swift 2.x) -> Sequence (Swift 3.0)
SequenceType在喵神的 Swifttips 里面已经讲解的很好了,我还是把自己的例子写了下来.这部分代码是 Swift3版本下的.
- public protocol SequenceType {
- associatedtype Iterator : IteratorProtocol
- //在3.0以前是GeneratorType
- ........
- }
IteratorProtocol又是什么呢?其实GeneratorType一样,可以理解为生成器
- public protocol IteratorProtocol {
- associatedtype Element
- public mutating func next() -> Self.Element?
- }
associatedtype Element要求实现这个协议的类必须定义一个名为Element的别名,这样一定程度上实现了泛型协议。协议同时要求实现next函数,其返回值是别名中定义的Element类型,next函数代表生成器要生成的下一个元素。
sample 是来自链接,写的非常清楚,我这只是贴贴我的 playground
- struct Book {
- var name: String = ""
- var price: Float = 0.0
- init(name: String, price: Float) {
- self.name = name
- self.price = price
- }
- }//定义一个 Book 的 Struct, 有书名和价格
- class BookListIterator: IteratorProtocol {
- typealias Element = Book //将 Book 类赋值 Element
- var currentIndex: Int =
- var bookList: [Book]?
- init(bookList: [Book]) {
- self.bookList = bookList
- } //初始化方法
- //用来遍历 bookList,直到返回 nil
- func next() -> BookListIterator.Element? {
- guard let list = bookList else { return nil }
- if currentIndex < list.count {
- let element = list[currentIndex]
- currentIndex +=
- return element
- } else {
- return nil
- }
- }
- }
现在IteratorProtocol这个生成器已经写好了,可以写 Sequence了
- class BookList: Sequence {
- var bookList: [Book]?
- init() {
- self.bookList = [Book]()
- }
- func addBook(book: Book) {
- self.bookList?.append(book)
- }
- // associatedtype Iterator : IteratorProtocol
- typealias Iterator = BookListIterator
- //public func makeIterator() -> Self.Iterator
- func makeIterator() -> BookList.Iterator {
- return BookListIterator(bookList: self.bookList!)
- }
- }
来试试写的 BookList:
- let bookList = BookList()
- bookList.addBook(book: Book(name: "Swift", price: 12.5))
- bookList.addBook(book: Book(name: "iOS" , price: 10.5))
- bookList.addBook(book: Book(name: "Objc", price: 20.0))
- for book in bookList {
- print("\(book.name) 价格 ¥\(book.price)")
- }
- // Swift 价格 ¥12.5
- // iOS 价格 ¥10.5
- // Objc 价格 ¥20.0
而且不止可以使用 for...in, 还可以用 map , filter 和 reduce.
再谈谈 Swift3的变化,其实就是变了GeneratorType To IteratorProtocol,就是这么任性....
从 Sequence 到 Collection
SequenceType(Swift 2.x) -> Sequence (Swift 3.0)
如果现在我们要看 bookList的 count, 就牵扯到了Collection这个协议,可以发现这个协议是对Indexable 和 Sequence 的扩展.
重点看看这个Indexable
在2.x的时候,Indexable 并没有继承任何其他协议,那么3.0来了,来了个IndexableBase:
public protocol Indexable : IndexableBase
那再来看IndexableBase:
- //2.x版本indexable
- var endIndex: Self.Index
- var startIndex: Self.Index
- subscript(_: Self.Index)
- //新增的下标以及实例方法
- subscript(_: Range<Self.Index>)
- func formIndex(after:)
- func index(after:)
再回到 Collection, 如果我们的类型已经遵循了Sequence,那么就只需要遵循:
- var startIndex: Int
- var endIndex: Int
- subscript(_: Self.Index)
- func index(after:)
这四个需求中,startIndex和endIndex是为了 Collection 中要遵循 Indexable协议,还得实现一个下标索引来获取对应索引元素.在 Swift3中,还需要声明 index(after:),关于这个戳swift-evolutionl链接.
再看看怎么对 Sample 例子中BookList遵循 Collection
- extension BookList: Collection {
- typealias Element = Book
- var startIndex: Int {
- return
- }
- var endIndex: Int {
- return bookList!.count
- }
- subscript(i: Int) -> Element {
- precondition((..<endIndex).contains(i), "index out of bounds")
- return bookList![i]
- }
- func index(after i: Int) -> Int {
- if i < endIndex {
- return i +
- } else {
- return endIndex
- }
- }
- }
是几个属性方法的实现还是挺简单的,现在BookList 这个 class,既遵循了 Sequence 和 Collection, 就有超过40种方法和属性可以使用:
- booklist.first //(Book(name: "Swift", price: 12.5))
- booklist.count //
- booklist.endIndex //
- booklist.isEmpty //false
现在自己创建的类型就已经遵循了 Sequence和 Collection,还有map,reduce 等函数式方法可以使用.
从Swift3的标准库协议看面向协议编程(一)的更多相关文章
- python第六天 函数 python标准库实例大全
今天学习第一模块的最后一课课程--函数: python的第一个函数: 1 def func1(): 2 print('第一个函数') 3 return 0 4 func1() 1 同时返回多种类型时, ...
- Swift中面向协议的编程
什么是面向协议的编程? 面向协议的编程,是一种编程范式. 编程范式,是一个计算机科学用语.维基百科中的解释是,计算机编程的基本风格或典型模式.通俗来说,就是解决某一个问题的方法不同方法和思路. 像大家 ...
- Android 面向协议编程 体会优雅编程之旅
Android中面向协议编程的深入浅出 http://blog.csdn.net/sk719887916/article/details skay编写 说起协议,现实生活中大家第一感觉会想到规则或者约 ...
- python:模块1——标准库简介
一.文档 windows系统:IDLE中打开帮助文档 Tutorial:简单入门 Library Reference:python内置函数和标准库(看不完的,当做字典来查)(此外还有pypi(拍派社区 ...
- AOP 面向切面编程
AOP http://blog.csdn.net/xiang_j2ee/article/details/6851963 Android 支持 AspectJ 这个库来实现面向切面编程. 使用 Apac ...
- 造轮子 | 怎样设计一个面向协议的 iOS 网络请求库
近期开源了一个面向协议设计的网络请求库 MBNetwork,基于 Alamofire 和 ObjectMapper 实现,目的是简化业务层的网络请求操作. 须要干些啥 对于大部分 App 而言,业务层 ...
- php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便)
php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便) 一.总结 直接看代码实例,特别方便易懂 thinkphp控制器利眠宁不支持(说明 ...
- C++ 标准库概览(一分钟就看完了)
C++ 标准库以若干头文件的方式提供. 下面简单介绍一个各头文件的内容. 第一部分 容器 Containers <array> C++11 新增.提供了容器类模板 std::array,固 ...
- fir.im Weekly - 揭秘 iOS 面向协议编程
本期 fir.im Weekly 重点推荐关于 iOS 面向协议编程相关文章,还有 iOS 多线程安全.Swift 进阶.Android MVVM 应用框架.Android 蓝牙实践等技术文章分享和工 ...
随机推荐
- Spring + Jedis集成Redis(单例redis数据库)
这几天没事,就把之前学习的redis代码整理一遍,废话不多说,上步骤. 1.pom.xml引入资源: <dependency> <groupId>org.springframe ...
- mysql 常用语句
1,查看索引使用情况的语句: explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explai ...
- linux下使用automake工具自动生成makefile文件
linux环境下,当项目工程很大的时候,编译的过程很复杂,所以需要使用make工具,自动进行编译安装,但是手写makefile文件比较复杂,所幸在GNU的计划中,设计出了一种叫做Autoconf/Au ...
- ASP.NET MVC中的错误处理
ASP.NET MVC中的错误的错误处理跨越了两个主要领域:程序异常和路由异常的处理.前者是关于在控制器和视图中捕获错误的;而后者更多是有关重定向和HTTP错误的. 1.在WebConfig中把过滤器 ...
- Nginx反向代理的工作方式
如图所示: 当客户端发来HTTP请求时,Nginx并不会立刻转发到上游服务器,而是先把用户的请求(包括HTTP包体)完整地接收到Nginx所在服务器的硬盘或者内存中,然后再向上游服务器发起连接,把缓存 ...
- LeetCode——Best Time to Buy and Sell Stock III (股票买卖时机问题3)
问题: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...
- sd卡脱机烧写系统的方法(测试成功)
一.sd卡烧写系统的基本思路: (1)把uboot.bin烧写到sd卡 (2)把image整个文件夹复制到sd卡 (3)开发板从sd卡启动,就开始自动烧写到nandflash中了. 二.烧写uboot ...
- B站开源ijkplayer 等多个项目
弹幕视频网 Bilibili(B 站)近日在 GitHub 网站上建立了开源工作组(BOSTF),用以分享与维护自己的开源项目,其中包括 DanmakuFlameMaster(燃烧吧!烈焰弹幕使)与 ...
- jQueryt过滤选择器
jQueryt过滤选择器 基本过滤选择器 选择器 描述 返回 示例 重要 :first 返回第一个元素 单个元素 :last 返回最后一个元素 单个元素 :not(selector) ...
- db2 import export load
DB2中所谓的数据移动,包括: 1. 数据的导入(Import) 2. 数据的导出(Export) 3. 数据的装入(Load) 导入和装入都是利用DB2的相关命令把某种格式的文件中的数据保存到数据库 ...