集合类型协议

1 Sequence协议

Sequence 协议是集合类型结构中的基础。一个序列 (sequence) 代表的是一系列具有相同类型的值,你可以对这些值进行迭代。 Sequence 协议提供了许多强大的功能,满足该协议的类型都可以直接使用这些功能。 如下是一个自定义实现Sequence的例子,Sequence协议提供很多功能,其中必须实现的只有一个迭代器,返回一个IteratorProtocol迭代器即可,所有关于Sequence的遍历筛选变形都是通过迭代器来实现的. 要实现自己的迭代器只需返回遵守IteratorProtocol协议的一个对象或者结构体即可.

//Sequence协议必须实现的部分
protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    func makeIterator() -> Iterator
}

//菲波那切数列的Sequence实现方式
struct FibsQueue: Sequence {
    let number: Int
    init(_ number: Int) {
        self.number = number
    }
    typealias Iterator = FibsIterator
    func makeIterator() -> FibsQueue.Iterator {
        return FibsIterator(number)
    }
}

2 IteratorProtocol协议

列通过创建一个迭代器来提供对元素的访问。迭代器每次产生一个序列的值,并且当遍历序列时对遍历状态进行管理。在 IteratorProtocol 协议中唯一的一个方法是 next(),这个方法需要在每次被调用时返回序列中的下一个值。当序列被耗尽时,next() 应该返回 nil.

//
“protocol IteratorProtocol {
    associatedtype Element
    mutating func next() -> Element?
}

/// “FibsIterator 迭代器可以产生一个斐波那契序列。它将记录接下来的两个数字,并作为状态存储,next 函数做的事情是为接下来的调用更新这个状态,并且返回第一个数。和之前的例子一样,这个迭代器也将产生“无穷”的数字,它将持续累加数字”
struct FibsIterator: IteratorProtocol {

    let number: Int
    var index: Int = 0

    init(_ number: Int) {
        self.number = number
    }

    var state = (0,1)
    mutating func next() -> Int? {

        if index >= number {
            return nil
        }
        index += 1

        let fibNumber = state.0
        state = (state.1,state.0+state.1)
        return fibNumber
    }
    typealias Element = Int
}

3 Collection协议

集合类型 (Collection) 指的是那些稳定的序列,它们能够被多次遍历且保持一致。除了线性遍历以外,集合中的元素也可以通过下标索引的方式被获取到。下标索引通常是整数,至少在数组中是这样。不过我们马上回看到,索引也可以是一些不透明值 (比如在字典或者字符串中),这有时候让使用起来不那么直观。集合的索引值可以构成一个有限的范围,它具有定义好了的开始和结束索引。也就是说,和序列不同,集合类型不能是无限的。

Collection协议是建立在Sequence协议上的. 除了从Sequence中集成了全部的方法以外,得益于可以获取指定位置的元素以及稳定迭代的保证,集合还获取了一些新的能力。比如 count 属性,如果序列是不稳定的,那么对序列计数将会消耗序列中的元素,这显然不是我们的目的。但是对于稳定的集合类型,我们就可以对其进行计数。

即使你用不到集合类型提供的这些特性,你依旧可以让你自己的序列满足 Collection 协议,这将告诉你的序列类型的使用者该序列是有限的,而且可以进行多次迭代。不过如果你只是想说明序列可以被多次迭代,但却必须去选一个合适的索引类型,确实会显得比较奇怪。在实现 Collection 协议时,最难的部分在于选取一个合适的索引类型来表达集合类型中的位置。这样设计的一个目的是,Swift 团队希望避免引入一个专门的可多次迭代序列的协议,因为它和 Sequence 拥有同样的要求,但是语义却不一致,这容易让用户感到迷惑。

//Collection协议,swift3,其中房噶和变量还是比较多的,但是很多都有了默认的实现,所以我们只需要实现少数几个即可
protocol Collection: Indexable,Sequence {
    associatedtype Iterator: IteratorProtocol = IndexingIterator<Self>
    associatedtype SubSequence: IndexableBase,Sequence = Slice<Self>
    associatedtype Indexdistance: SignedInteger = Int
    associatedtype Indices: IndexableBase,Sequence = DefaultIndices<Self>
    
    var first: Iterator.Element? { get }
    var indices: Indices { get }
    var isEmpty: Bool { get }
    var count: Indexdistance { get }
    
    func makeIterator() -> Iterator
    func prefix(through position: Index) -> SubSequence
    func prefix(upTo end: Index) -> SubSequence
    func suffix(from start: Index) -> SubSequence
    func distance(from start: Index,to end: Index) -> Indexdistance
    func index(_ i: Index,offsetBy n: Indexdistance) -> Index
    func index(_ i: Index,offsetBy n: Indexdistance,limitedBy limit: Index) -> Index?
    
    subscript(position: Index) -> Iterator.Element { get }
    subscript(bounds: Range<Index>) -> SubSequence { get }
}

一个自定义实现FIFO队列的例子

//自定义一个队列
//首先定义好队列到底是什么,我们可以用协议来描述队列是社么
/// 一个能够将元素入队和出队的类型
protocol Queue {
    /// 在 `self` 中所持有的元素的类型
    associatedtype Element
    /// 将 `newElement` 入队到 `self`
    mutating func enqueue(_ newElement: Element)
    /// 从 `self` 出队一个元素
    mutating func dequeue() -> Element?
}

//实现一个队列,FIFO队列,其中元素类型是`Element`
struct FIFOQueue<Element>: Queue {
    fileprivate var left: [Element] = []
    fileprivate var right: [Element] = []
    /// 将元素添加到队列最后
    /// - 复杂度: O(1)
    mutating func enqueue(_ newElement: Element) {
        right.append(newElement)
    }
    /// 从队列前端移除一个元素
    /// 当队列为空时,返回 nil
    /// - 复杂度: 平摊 O(1)
    mutating func dequeue() -> Element? {
        if left.isEmpty {
            left = right.reversed()
            right.removeAll()
        }
        return left.popLast()
    }
}

//遵守 Collection 协议
extension FIFOQueue: Collection {
    public var startIndex: Int { return 0 }
    public var endindex: Int { return left.count + right.count }
    public func index(after i: Int) -> Int {
        precondition(i < endindex)
        return i + 1
    }
    public subscript(position: Int) -> Element {
        precondition((0..<endindex).contains(position),"Index out of bounds")
        if position < left.endindex {
            return left[left.count - position - 1]
        } else {
            return right[position - left.count]
        }
    }
}

//ExpressibleByArrayLiteral协议
extension FIFOQueue: ExpressibleByArrayLiteral {
    public init(arrayLiteral elements: Element...) {
        self.init(left: elements.reversed(),right: [])
    }
}

4 ExpressibleByArrayLiteral协议

当实现一个类似队列这样的集合类型时,最好也去实现一下 ExpressibleByArrayLiteral。这可以让用户能够以他们所熟知的 [value1,value2,etc] 语法创建一个队列。

extension FIFOQueue: ExpressibleByArrayLiteral {
    public init(arrayLiteral elements: Element...) {
        self.init(left: elements.reversed(),right: [])
    }
}

'Self' is only available in a protocol or as the result of a method in a class; ...

Reference: Swift进阶

Swift中的集合类型协议的更多相关文章

  1. 使用layui实现左侧菜单栏及动态操作tab项的方法

    这篇文章主要介绍了使用layui实现左侧菜单栏及动态操作tab项的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. 在iOS上绘制扭曲的文本

    使用iOS9及更高版本中提供的标准API,如何在绘制文本时实现扭曲效果?

  3. ios – 如果Element符合给定的协议,则扩展阵列以符合协议

    如果是这样,语法是什么?解决方法Swift4.2在Swift4.2中,我能够使用符合这样的协议的元素扩展数组:

  4. ios – 如何在swift中获取2数组的常见元素列表

    (双关语)编辑:,你可以这样做这个实现是丑陋的.

  5. Swift 函数Count,Filter,Map,Reduce

    Count-统计数量文档示例Filter-条件过滤文档示例-过滤长度大于4的字符串也可以简化Map-映射集合类型,返回数组文档示例同样可以简化Reduce-把数组结合到一起文档示例可以简化进一步简化

  6. Swift语法——Swift Sequences 探究

    今天看到Array的API中有这么一个声明的函数:函数名为extend,所需参数是S类型的newElements,而S首先要实现SequenceType协议。看看APTGeneratorType必须要实现一个函数next(),它的作用就是返回一个Element,注释里说的很清楚:它的作用就是一直返回元素,直到最后。1)Swift调用generate()来生成了一个Generator,这个对象是一个私有的变量即__g;2)__g调用了next()函数,返回了一个optional类型对象element?。这个

  7. Swift 中数组和链表的性能

    尽管如此,我觉得链表的例子非常有意思,而且值得实现和把玩,它有可能会提升数组reduce方法的性能。同时我认为Swift的一些额外特性很有趣:比如它的枚举可以灵活的在对象和具体方法中自由选择,以及“默认安全”。这本书未来的版本可能就会用Swift作为实现语言。拷贝数组消耗的时间是线性的。使用链表还有其他的代价——统计链表节点的个数所需要的时间是统计数组元素个数时间的两倍,因为遍历链表时的间接寻址方式是需要消耗时间的。

  8. Swift中集合类型indexOf(Element)提示错误的解决办法

    简单的竟然出错了!其实看一下错误描述,大概就可以猜到Swift此时不知道你自定义类是如何比较的,如果是Swift内置的各种struct和class就不存在这个问题,比如:解决很简单,添加一个==方法即可:最后补充一下,早期版本的Swift还有一个find函数可以完成类似的功能,但是新版本已经没有该函数了,So你懂的…

  9. swift map reduce 获取下标(index)的方法

    原文:http://stackoverflow.com/questions/28012205/map-or-reduce-with-index-in-swiftYoucanuseenumeratetoconvertasequence(Array,String,etc.)toasequenceoftupleswithanintegercounterandandelementpairedtogethe

  10. Swift中的map 和 flatMap 原理及用法

    map和flatMap是Swift中两个常用的函数,它们体现了Swift中很多的特性。对于简单的使用来说,它们的接口并不复杂,但它们内部的机制还是非常值得研究的,能够帮助我们够好的理解Swift语言。map简介首先,咱们说说map函数如何使用。letnumbers=[1,2,3,4]letresult=numbers.map{$0+2}print//[3,4,5,6]map方法接受一个闭包作为参数,然后它会遍历整个numbers数组,并对数组中每一个元素执行闭包中定义的操作。比如咱们这个例子里面的闭包是讲

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部