Swift编程语言中如何实现自定义类型的for-in循环(基于Swift 2.2)

我们在Swift编程语言中常常会用到for-in循环(在编程语言术语中又被称为for-each)。此外,从Swift 2.2版本起,for循环将只支持for-in形式,而不支持for i = 0; i < n; i+=1 { }这种形式了,若要使用这种形式的话,只得用while或repeat-while来代替,或想办法转为for-in。

在Swift中,标准库已经定义了许多类型可直接支持for-in循环形式,比如Range、Array、Set、Dictionary等等。那么我们是否能自己定义一个类或结构体来支持for-in这种迭代形式呢?当然可以!我们要实现这个目标需要分两步走。

第一步,我们要使用for-in循环的类或结构体需要实现SequenceType这个协议。SequenceType包含了许多容器相关的接口方法,但如果我们只需要简单实现for-in循环的话,那么只需要实现其 public func generate() -> Self.Generator 接口方法即可。这里的Self只能用在protocol的定义内,相当于self,但是这里又不能用self,因为self是对对象的引用,协议不是一个对象,所以Swift编程语言中引入了Self(注意S是大写的)表示引用本协议内定义的类型。generate方法用于生成所需迭代的每个元素的列表。此外,Generator的本体是GeneratorType,它也是一个protocol,表示所需迭代的每个元素对象,所以我们要做第二步。

第二步,实现GeneratorType协议。这个协议比较简单,就一个 public mutating func next() -> Self.Element 接口方法。这里的Element可用来指定每个元素的类型。

下面我们就看一下一个实例代码:

//
//  ViewController.swift
//  SwiftTest
//
//  Created by Zenny Chen on 16/4/1.
//  Copyright © 2016年 GreenGames Studio. All rights reserved.
//

import Cocoa

class MyIterContainer<T> : SequenceType {

    // 容器本身包含一个数组对象mElemArray
    private var mElemArray: [T]?

    init() {
        mElemArray = [T]()
    }

    init(elems: [T]) {
        mElemArray = elems;
    }

    func generate() -> MyIterGenerator<T> {

        // 这里返回一个GeneratorType对象
        return MyIterGenerator(elems: mElemArray!)
    }
}

class MyIterGenerator<T> : GeneratorType {

    private var mCurrentIndex: Int = 0
    private var mElemArray: [T]?

    init(elems: [T]) {

        mElemArray = elems
    }

    func next() -> T? {

        guard let list = mElemArray else { return  nil }

        if mCurrentIndex < list.count {

            let element = list[mCurrentIndex]
            mCurrentIndex += 1
            return element

        }
        else {
            return nil
        }
    }
}

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        let container = MyIterContainer(elems: [1, 2, 3, 4])

        var sum = 0
        for i in container {
            sum += i
        }
        print("sum = \(sum)")

        sum = 0

        // 上述的for-in迭代就相当于以下代码:
        let generator = container.generate()
        var elem: Int? = nil

        repeat {
            elem = generator.next()
            if let value = elem {
                sum += value
            }
        }
        while elem != nil

        print("second sum = \(sum)")
    }

    override var representedObject: AnyObject? {
        didSet {
            // Update the view, if already loaded.
        }
    }
}

上述示例代码先定义了一个容器类MyIterContainer<T>,然后定义了与之相关的生成器类MyIterGenerator<T>,这里用了泛型,可使得后面的实现更为灵活。然后在viewDidLoad方法中描述了for-in的使用方法,并且在最后描述了其内部实现机制。

时间: 2024-11-10 07:10:32

Swift编程语言中如何实现自定义类型的for-in循环(基于Swift 2.2)的相关文章

Swift编程语言中的方法引用(基于2.2版本)

由于Apple官方的<The Swift Programming Guide>对Swift编程语言中的方法引用介绍得不多,所以这里将更深入.详细地介绍Swift中的方法引用. Swift与Objective-C不同,由于Objective-C的方法都属于“消息”,因此直接用selector的消息签名即可表示一条确定的消息作为方法引用.而Swift的方法更类似于C++.Java中的方法,也就是说比Objective-C更静态,因此它不具有如此般灵活性. 另外,在Swift编程语言中,方法引用与C

【hash_map】hash_map中键为自定义类型的操作

class person { public: string name; int age; person(string s,int i):name(s),age(i){} }; struct person_hash { static const size_t bucket_size = 4; static const size_t min_buckets = 8; //哈希值函数 size_t operator()(const person &p)const { //原来使用 return has

swift基础语法(控制流、可选类型、switch、循环、开闭空间)

1 // Playground - noun: a place where people can play 2 3 import Cocoa 4 5 //控制流 6 7 //Swift的条件语句包括if和switch,循环语句包含for-in.for.while和do-while,循环/判断条件不需要括号,但循环/判断体(body)必需括号: 8 let individualScores = [75, 43, 103, 87, 12] 9 var teamScore = 0 10 for sco

struts2自定义类型转换器

首先,何为struts2的类型转换器? 类型转换器的作用是将请求中的字符串或字符串数组参数与action中的对象进行相互转换. 一.大部分时候,使用struts2提供的类型转换器以及OGNL类型转换机制即可满足大部分类型转换需求.如: 类User.java package models; public class User { private String username; private String password; public String getUsername() { retur

Android进阶AIDL使用自定义类型

原文首发于微信公众号:jzman-blog 上篇文章 中主要介绍从 AIDL 的使用方式以及 Android 开发中不同进程之间的通信,遗留的问题是如何在 AIDL 中使用自定义类型,具体步骤如下: 创建自定义类型 声明自定义类型 定义与自定义类型相关的业务 重写业务实体类 远程调用 验证 AIDL 1. 创建自定义类型 自定义类型传输的就是一个实体对象,这个实体类必须实现 Parcelable 接口,具体如下: // 自定义类型 public class Work implements Par

Swift编程语言学习1.5——类型别名、布尔值、元组

类型别名 类型别名(type aliases)就是给现有类型定义另一个名字.你可以使用typealias关键字来定义类型别名. 当你想要给现有类型起一个更有意义的名字时,类型别名非常有用.假设你正在处理特定长度的外部资源的数据: typealias AudioSample = UInt16 定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名: var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 现在是 0 本例中,A

iOS中生成并导入基于Swift编程语言的Framework

从iOS 8.0开始就引入了framework打包方式以及Swift编程语言.我们可以主要利用Swift编程语言将自己的代码打包成framework.不过当前Xcode 7.x在自动导入framework包的时候不太智能,因此需要做一些善后处理. 首先,在生成framework时,要暴露给外部的结构体.类.枚举.函数等都需要用public关键字来修饰,否则外部是访问不到这些类型以及函数的.此外,在结构体和类中,不能缺省初始化方法,必须用public暴露给外部,否则也一样无法被访问到. 其次,当我

Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似。

闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似. 闭包可以 捕获 和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包.Swift会为您管理在 捕获 过程中涉及到的内存操作. 注意:如果您不熟悉 捕获 (capturing) 这个概念也不用担心,后面会详细对其进行介绍. 在Swift函数章节中介绍的全局和嵌套函数实际上也是特殊的

Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較类似。

闭包是功能性自包括模块,能够在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其它一些编程语言中的 lambdas 比較相似. 闭包能够 捕获 和存储其所在上下文中随意常量和变量的引用. 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包.Swift会为您管理在 捕获 过程中涉及到的内存操作. 注意:假设您不熟悉 捕获 (capturing) 这个概念也不用操心.后面会具体对其进行介绍. 在Swift函数章节中介绍的全局和嵌套函数实际上也是特殊的