美文网首页
Sequence(转)(创建一个类可以直接使用for ...in

Sequence(转)(创建一个类可以直接使用for ...in

作者: 傻傻小萝卜 | 来源:发表于2016-07-02 09:28 被阅读119次

原文地址:http://www.cnblogs.com/theswiftworld/p/swift-sequence.html

Swift 语言中提供了一种 for .. in 语法的形式,用于遍历集合,比如对于 Array 类型,就可以用 for .. in 来进行遍历。这个语法在很多其他语言中也有提供,省去了我们定义下标的操作。今天我们要了解的就是关于 for .. in 语法的原理,我们可以让我们自己的类也支持这个语法。

何为 for .. in

首先,我们先来了解一下 for .. in 的用法,比如这段代码:

letbookList = ["Swift","iOS","Objc"]

forbookNameinbookList {

print(bookName)

}

我们定义了一个数组bookList, 里面存放了三个字符串。然后我们就可以通过 for ... in 循环进行遍历。

数组其实就是 Array 类,我们上面的定义如果写的详细些,应该是这样:

letbookList:Array= ["Swift","iOS","Objc"]

也就是说,我们传递给 for ... in 语法的,其实是一个 Array 类的实例。那么我们再来看看 Array 类的继承关系:

publicstructArray :CollectionType,MutableCollectionType,_DestructorSafeContainer{

...

}

它继承自一个叫做 CollectionType 的协议,然后我们再来看一下 CollectionType 的定义:

publicprotocolSequenceType{

...

}

经过这么一连串的追溯,其实关键就在于这个 SequenceType,一个类如果实现了 SequenceType 协议,那么他就可以使用 for ... in 语法进行遍历了。包括我们自己的定义的类。

如何实现 SequenceType 协议

那么,既然我们知道了这个特性,我们就可以让自己定义的类也支持 for .. in 语法。我们先定义一个实体类 Book:

classBook{

var name:String=""

var price:Float= 0.0

init(name:String, price:Float) {

self.name = name

self.price = price

}

}

Book 类有两个属性,一个是书名,一个是价格,然后还有一个构造方法。

接下来,我们再定义一个类 BookList,它实现了 SequenceType 协议,用来表示 Book 实例的列表。不过再实现之前,我们先看一看 SequenceType 协议都需要实现那些接口:

classBookList:SequenceType{

...

typealias Generator=BookListGenerator

func generate() ->Generator{

return BookListGenerator(bookList:self.bookList!)

}

}

SequenceType 协议中定义了一个 typealias Generator 的属性,这个属性是一个继承自 GeneratorType 的类。

SequenceType 还定义了一个 generate 方法,用于返回我们指定的 GeneratorType 类型。

恩。。 怎么又多了个 GeneratorType, 好像有点复杂的样子。那么咱们继续看,GeneratorType 是实际生成遍历信息的接口,我们这里的 BookListGenerator 实现了这个协议,那就来看一下代码吧:

class BookListGenerator:GeneratorType{

typealias Element=Book

var currentIndex:Int= 0

var bookList:[Book]?

init(bookList: [Book]) {

self.bookList = bookList

}

func next() ->Element? {

guard letlist = bookListelse{returnnil}

if currentIndex < list.count{

let element = list[currentIndex]

currentIndex++

return element

}else{

return nil

}

}

}

代码稍长,请听我给大家一一分解~

首先,GeneratorType 定义了一个属性别名: typealias Element。 我们将 Book 类赋值给它,表示我们这个集合中存储的数据类型是 Book 类的实例。

接下来,GeneratorType 还定义了一个 next 方法。用于遍历这个集合,直到 next 方法返回 nil 的时候,遍历结束。

fun cnext() ->Element? {

guard letlist = bookListelse{returnnil}

if currentIndex < list.count{

let element = list[currentIndex]

currentIndex++

return element

}else{

return nil

}

}

next 方法中,先用 guard 关键字进行了一次判断,检查 bookList(也就是实际的数据是否为空),如果为空,就直接返回 nil。 宣告遍历结束~

接下来,用了一个叫做 currentIndex 的属性表示当前所遍历到得索引,这个属性的初始值是 0,然后每遍历一个元素,就加 1,直到它的值超出 list.count 的值,就会返回 nil,宣告遍历完成~

这样,我们的 BookListGenerator 就定义完成了(当然,它还声明了一个构造方法,由于实在简单,我们就不多说了~)。再次回到继承自 SequenceType 的 BookList 类中:

classBookList:SequenceType{

private varbookList:[Book]?

init() {

self.bookList = [Book]()

}

func addBook(book:Book){ 

self.bookList?.append(book)

}

typealias Generator=BookListGenerator

func generate() ->Generator{

return BookListGenerator(bookList:self.bookList!)

}

}

这次列出了所有的代码,还是一一分解~

看了上面关于 BookListGenerator 类的定义,相信就不难理解这里的代码了:

typealias Generator=BookListGenerator

func generate() ->Generator{

return BookListGenerator(bookList:self.bookList!)

}

这两个 SequenceType 接口的方法我们再来观摩下,typealias 就不用多说了,generate 方法会再遍历开始的时候调用一次,每次遍历都会构建一个 Generator 实例,我们这个 BookList 中构建的就是 BookListGenerator,并传入了 self.bookList(这个是实际的数据列表)以供 BookListGenerator 来进行具体的遍历操作。

其他方面嘛,BookList 类还定了一个私有属性,用于实际存放 Book 的列表数据:

privatevarbookList:[Book]?

还提供了一个构造方法,和一个 addBook 方法,供我们使用,这两个方法比较简单,就不多说啦。

使用我们的 SequenceType 类型

好了,我们的 BookList 就这样完工啦。现在轮到我们检验一下了:

let bookList =BookList()

bookList.addBook(Book(name:"Swift", price: 12.5))

bookList.addBook(Book(name:"iOS", price: 10.5))

bookList.addBook(Book(name:"Objc", price: 20.0))

for booki nbookList {

print("\(book.name) 价格 ¥\(book.price)")

}

大功告成,我们声明了 BookList 类,然后用 addBook 方法添加几本书进来。接着我们就可以用 for .. in 来遍历这个集合啦。

结语

经过这一系列的折腾,我们实现了 SequenceType 和 GeneratorType 类型的定义,并实现 for .. in 的循环遍历。以及了解了这背后的原理。当然,我在这里也只是给大家介绍了一个点,大家还可以在swiftdoc.org查看这几个协议的详细文档,里面介绍的更加全面。

另外,关于 Swift 语言特性知识的内容,还可以看一看这几篇内容:

Swift 中的利刃,函数和闭包

神奇的 Currying

Swift 中的引用类型与值类型

最后,感谢大家花了这么长时间把这篇文章看完。希望给大家提供更多有价值的内容,期待大家的宝贵意见。

相关文章

  • Sequence(转)(创建一个类可以直接使用for ...in

    原文地址:http://www.cnblogs.com/theswiftworld/p/swift-sequenc...

  • python 类和对象

    类是创建对象的模板,对象是类的实例。类包含有属性和方法,类不可以直接使用,必须实例化之后才可以使用。 a、类的创建...

  • Ten Day(面向对象Ⅳ)

    static的使用 静态函数可以直接使用类名来调用,无需创建对象。

  • 初识Java||使用类方法的注意事项

    类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用。 类方法不能够直接操作实例变量 如果一个方法使用...

  • Java多线程基础补充

    使用Callable接口和FutureTask来创建线程 创建Callable的实现类,实现call方法,可以直接...

  • Python Qt GUI设计:QMainWindow、QWid

    QMainWindow、QWidget和QDialog三个类都是用来创建窗口的,可以直接使用,也可以继承后再使用,...

  • oracle主键自增

    创建序列语法: 创建案例: 创建sequence 使用触发器实现ID递增 创建序列

  • Java String类

    一.创建字符串 1.直接创建 编译器会使用该值创建一个 String 对象 String类是不可以改变的,所以一旦...

  • 内部类

    内部类:在一个类内部定义的类 内部类属于外部类的一个成员,所以内部类可以直接使用外部类的成员 直接创建内部类的对象...

  • 100 mysql 中创建自增的序列(Sequence)

    mysql 中创建自增的序列(Sequence)由于mysql和oracle不太一样,不支持直接的sequence...

网友评论

      本文标题:Sequence(转)(创建一个类可以直接使用for ...in

      本文链接:https://www.haomeiwen.com/subject/qhdqjttx.html