数据结构

变量与常量

常量和变量把一个名字(比如 maximumNumberOfLoginAttempts 或者 welcomeMessage)和一个指定类型的值(比如数字 10 或者字符串"Hello")关联起来。常量的值一旦设定就不能改变,而变量的值可以随意更改。常量和变量必须在使用前声明,用 let 来声明常量,用 var 来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数:

//基本使用
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0

//定义变量
var myVariable = 123

//定义常量
let myConstantVariable = 123

// 隐式指定整数类型
var anInteger = 2

// 明确指定整数类型
let anExplicitInteger :Int = 2

你可以在一行中声明多个常量或者多个变量,用逗号隔开:

var x = 0.0, y = 0.0, z = 0.0

常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制表符。也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。

类型标注

当你声明常量或者变量的时候可以加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。如果要添加类型标注,需要在常量或者变量名后面加上一个冒号和空格,然后加上类型名称。

类型安全与类型推测

Swift 是一个类型安全(type safe )的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个String,你绝对不可能不小心传进去一个Int。由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误。当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需要显式指定类型。如果你没有显式指定类型,Swift 会使用类型推测(type inference)来选择合适的类型。有了类型推测,编译器可以在编译代码的时候自动推测出表达式的类型。原理很简单,只要检查你赋的值即可。

因为有类型推测,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但是大部分工作并不需要你自己来完成。当你声明常量或者变量并赋初值的时候类型推测非常有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value或literal)即可触发类型推测。(字面量就是会直接出现在你代码中的值,比如42和3.14159。)

别名

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

类型判断与转换

as、as?、as!

在 Swift 1.2 版本之前,都是使用as关键字来进行类型的转换,而是否是强制转换则是根据上下文而定,在 Swift 1.2 之后,将as关键字拆分为了as!as?这两个单独的操作符,其具体的用法可以参考如下:

class Animal {}
class Dog: Animal {}

let a: Animal = Dog()
a as Dog		// now raises the error:  "'Animal is not convertible to 'Dog';
				// ... did you mean to use 'as!' to force downcast?"

a as! Dog		// forced downcast is allowed

let d = Dog()
d as Animal		// upcast succeeds
class Animal {}

class Cat: Animal {}

class Dog: Animal {
	var name = "Spot"
}

let dog: Dog? = nil
dog?.name		// evaluates to nil
dog!.name		// triggers a runtime error

let animal: Animal = Cat()
animal as? Dog	// evaluates to nil
animal as! Dog	// triggers a runtime error

基本类型

AnyObject

数值类型

整数就是没有小数部分的数字,比如 42 和-23。整数可以是有符号(正、负、零)或者无符号(正、零)。Swift 提供了 8,16,32 和 64 位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,比如 8 位无符号整数类型是 UInt8,32 位有符号整数类型是 Int32。就像 Swift 的其他类型一样,整数类型采用大写命名法。

  • 整数范围

你可以访问不同整数类型的 min 和 max 属性来获取对应类型的最大值和最小值:

let minValue = UInt8.min  // minValue 为 0,是 UInt8 类型的最小值 let maxValue = UInt8.max  // maxValue 为 255,是 UInt8 类型的最大值
类型 长度 说明
Int -2147483648~2147483647
UInt 注意:尽量不要使用 UInt,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用 Int,即使你要存储的值已知是非负的。统一使用 Int 可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推测,请参考类型安全和类型推测
浮点数 Double 表示 64 位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。Float 表示 32 位浮点数。精度要求不高的话可以使用此类型 Double 精确度很高,至少有 15 位数字,而 Float 最少只有 6 位数字。选择哪个类型取决于你的代码需要处理的值的范围

随机数

科学计算

类型转换

布尔类型

Swift 有一个基本的布尔(Boolean)类型,叫做Bool。布尔值指逻辑上的(logical),因为它们只能是真或者假。Swift 有两个布尔常量,true和false:
let orangesAreOrange = true let turnipsAreDelicious = false
orangesAreOrange和turnipsAreDelicious的类型会被推测为Bool,因为它们的初值是布尔字面量。就像之前提到的Int和Double一样,如果你创建变量的时候给它们赋值true或者false,那你不需要将常量或者变量声明为Bool类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推测,这让 Swift 代码更加简洁并且可读性更高。

当你编写条件语句比如if语句的时候,布尔值非常有用:
    if turnipsAreDelicious {
        println("Mmm, tasty turnips!")
    } else {
        println("Eww, turnips are horrible.")
    }
    // 输出 "Eww, turnips are horrible."

条件语句,例如 if,请参考控制流。如果你在需要使用 Bool 类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:

let i = 1 if i {     // 这个例子不会通过编译,会报错 }

然而,下面的例子是合法的:

let i = 1 if i == 1 {     // 这个例子会编译成功 }
i == 1的比较结果是Bool类型,所以第二个例子可以通过类型检查。类似i == 1这样的比较,请参考基本操作符。和 Swift 中的其他类型安全的例子一样,这个方法可以避免错误并保证这块代码的意图总是清晰的。

空类型

可选类型(Optional)

Swift 语言使用 var 定义变量,但和别的语言不同,Swift 里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错:

var stringValue : String
//error: variable 'stringValue' used before being initialized
//let hashValue = stringValue.hashValue
let hashValue = stringValue.hashValue

Optional 其实是个enum,里面有NoneSome两种类型。其实所谓的 nil 就是Optional.None, 非 nil 就是Optional.Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用 Optional 的时候要拆包(从 enum 里取出来原始值)的原因, 也是 PlayGround 会把 Optional 值显示为类似{Some "hello world"}的原因,这里是 enum Optional 的定义:

enum Optional<T> : LogicValue, Reflectable {
    case None
    case Some(T)
    init()
    init(_ some: T)

    /// Allow use in a Boolean context.
    func getLogicValue() -> Bool

    /// Haskell's fmap, which was mis-named
    func map<U>(f: (T) -> U) -> U?
    func getMirror() -> Mirror
}

声明为 Optional 只需要在类型后面紧跟一个?即可。如:

var strValue: String?   //?相当于下面这种写法的语法糖
var strValue: Optional<String>

上面这个 Optional 的声明,意思不是”我声明了一个 Optional 的 String 值”, 而是”我声明了一个 Optional 类型值,它可能包含一个 String 值,也可能什么都不包含”,也就是说实际上我们声明的是 Optional 类型,而不是声明了一个 String 类型,这一点需要铭记在心。

一旦声明为 Optional 的,如果不显式的赋值就会有个默认值 nil。判断一个 Optional 的值是否有值,可以用 if 来判断:

if strValue {
    //do sth with strValue
}

缘由

为什么要这么设计呢?苹果官方给出的解释是,因为 Swift 是一门类型安全的语言。从前面的例子中可以看出,Swift 的可选类型会进行编译检查,防止一些常见的运行时错误。让我们看一看下面的例子,这样可以更好地理解。 比如说,在 Objective-C 中有如下代码:

- (NSString *)findStockCode:(NSString *)company {
   if ([company isEqualToString:@"Apple"]) {
       return @"AAPL";
   } else if ([company isEqualToString:@"Google"]) {
       return @"GOOG";
   }

   return nil;
}

在上面的方法里,你可以用 findStockCode 方法来获取到股票的代码,显然只有 Apple 和 Google 的查询会返回值,其他情况都会返回 nil。 假设我们在下面的代码中会调用这个方法:

NSString *stockCode = [self findStockCode:@"Facebook"]; // nil is returned
NSString *text = @"Stock Code - ";
NSString *message = [text stringByAppendingString:stockCode]; // runtime error
NSLog(@"%@", message);

这段代码在编译时不会有任何问题,但是如果输入的是 Facbook 则会返回 nil,导致运行时错误。而在 Swift 里,和运行时错误不用,Swift 会在编译时就提示错误信息,我们可以把上面的代码在 Swift 中重写:

func findStockCode(company: String) -> String? {
   if (company == "Apple") {
      return "AAPL"
   } else if (company == "Google") {
      return "GOOG"
   }

   return nil
}

var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
let message = text + stockCode  // compile-time error
println(message)

在上面的代码里,stockCode 被定义成了可选类型,这意味着它可以有一个 string 的值,也可以为 nil。代码无法通过编译,会提示一个错误:value of optional type String? is not unwrapped。正如你在例子中看到的,Swift 的可选类型加强了 nil 检测,为开发者提供了编译时的检查,合理的使用可选类型可以有效地提高代码质量。

强制解析

注意,一旦声明为可选类型,就不再是原来的普通类型了,虽然只是简单的加了个?。对于 Optional 值,不能直接进行操作,否则会报错:

//error: 'String?' does not have a member named 'hashValue'
//let hashValue = strValue.hashValue
//                ^        ~~~~~~~~~

let hashValue = strValue.hashValue

如果需要获取到可选类型中的值,就要用到了!表达式:

let hashValue = strValue!.hashValue
//对于上面的股票代码
var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
if stockCode {
    let message = text + stockCode!
    println(message)
}

可选绑定

除了强制解析,可选绑定 (optional binding) 是一个更值得推荐的解析方案。你可以用可选绑定来检测一个可选类型的值有没有值,如果有值则解析出来并存储到一个临时的变量里。

var stockCode:String? = findStockCode("Facebook")
let text = "Stock Code - "
if let tempStockCode = stockCode {
    let message = text + tempStockCode
    println(message)
}

代码中的 if let (或者 if var ) 是可选绑定的两个关键词。翻译成人类语言,大概是这个样子:“如果 stackCode 它有值,把它的值存到 tempStackCode 里,然后继续执行接下来的代码块。如果它没值,跳过后面的代码块。” 因为 tempStockCode 是一个新的常量,所以你不再需要添加 ! 后缀。

可选链

可选链用于在类包裹的多个可选类型的层次调用中,譬如上面的获取股票的函数如果放到一个类中:

class Stock {
    var code: String?
    var price: Double?
}

func findStockCode(company: String) -> Stock? {
    if (company == "Apple") {
        let aapl: Stock = Stock()
        aapl.code = "AAPL"
        aapl.price = 90.32

        return aapl

    } else if (company == "Google") {
        let goog: Stock = Stock()
        goog.code = "GOOG"
        goog.price = 556.36

        return goog
    }

    return nil
}

接下来,我们先用 findStockCode 函数查找股票的代码,然后计算购买 100 股所需要的总价:

if let stock = findStockCode("Apple") {
    if let sharePrice = stock.price {
        let totalCost = sharePrice * 100
        println(totalCost)
    }
}

函数的返回值是可选类型,我们通过可选绑定来检测是否有值,显然股票的价格也是一个可选类型,于是我们继续使用 if let 来检测它是否有值。上面的代码没有任何问题,不过这一层一层的 if 嵌套实在是太麻烦了,如果可选类型层次多点,很可能形成下面的情况:

if let x = xxx() {
    if let x = xxx() {
        if let x = xxx() {
            if let x = xxx() {
                if let x = xxx() {
                    if let x = xxx() {
                        if let x = xxx() {
                            if let x = xxx() {
                                if let x = xxx() {
                                    if let x = xxx() {
                                        if let x = xxx() {
                                            if let x = xxx() {

                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

除了使用 if let,我们可以通过可选链来简化代码。我们可以用问号将多个可选类型串联起来:


if let sharePrice = findStockCode("Apple")?.price {
    let totalCost = sharePrice * 100
    println(totalCost)
}

可选链提供了访问变量的另一种方式,代码现在看上去也更加的干净整洁。上面只是一个基础的使用,更加深入的学习可以参考官方文档。

Examples

可选类型用于 Protocol 可选方法

可选类型用于未实例化控件

考虑下这一种情况,我们有一个自定义的MyViewController类,类中有一个属性是myLabel,myLabel 是在 viewDidLoad 中进行初始化。因为是在 viewDidLoad 中初始化,所以不能直接声明为普通值:var myLabel : UILabel,因为非 Optional 的变量必须在声明时或者构造器中进行初始化,但我们是想在 viewDidLoad 中初始化,所以就只能声明为 Optional:var myLabel: UILabel?, 虽然我们确定在 viewDidLoad 中会初始化,并且在 ViewController 的生命周期内不会置为 nil,但是在对 myLabel 操作时,每次依然要加上!来强制拆包,比如:

myLabel!.text = "text"
myLabel!.frame = CGRectMake(0, 0, 10, 10)
...

时间日期

NSDate

在 Objective-C 中,可以使用如下的代码创建一个 UTC 的时间:

NSDate *currentUTCDate = [NSDate date]

但是在 Swift 中,如果使用如下方式:

let date = NSDate()

获取到的会是本地时间。

UTC 时间与本地化时间

import UIKit

let date = NSDate();
// "Apr 1, 2015, 8:53 AM" <-- local without seconds

var formatter = NSDateFormatter();
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss ZZZ";
let defaultTimeZoneStr = formatter.stringFromDate(date);
// "2015-04-01 08:52:00 -0400" <-- same date, local, but with seconds
formatter.timeZone = NSTimeZone(abbreviation: "UTC");
let utcTimeZoneStr = formatter.stringFromDate(date);
// "2015-04-01 12:52:00 +0000" <-- same date, now in UTC

时间比较

如果需要比较两个日期,可以使用如下方法,在如下代码中已经展示了如何处理不同的返回结果:

// Date comparision to compare current date and end date.
var dateComparisionResult:NSComparisonResult = NSDate().compare(endDate)

if dateComparisionResult == NSComparisonResult.OrderedAscending
{
    // Current date is smaller than end date.
}
else if dateComparisionResult == NSComparisonResult.OrderedDescending
{
    // Current date is greater than end date.
}
else if dateComparisionResult == NSComparisonResult.OrderedSame
{
    // Current date and end date are same.
}

TimeStamp

如果需要将某个 TimeStamp("/Date(1427909016000-0800)”)转化为 NSDate 对象,那么可以使用如下的扩展工具,该扩展将会把 TimeStamp 转化为本地化时间。其中 1427909016000 表示从 Unix 计时以来的毫秒数,而-0800 表示时区:

extension NSDate {
    convenience init?(jsonDate: String) {
        let prefix = "/Date("
        let suffix = ")/"
        let scanner = NSScanner(string: jsonDate)

        // Check prefix:
        if scanner.scanString(prefix, intoString: nil) {

            // Read milliseconds part:
            var milliseconds : Int64 = 0
            if scanner.scanLongLong(&milliseconds) {
                // Milliseconds to seconds:
                var timeStamp = NSTimeInterval(milliseconds)/1000.0

                // Read optional timezone part:
                var timeZoneOffset : Int = 0
                if scanner.scanInteger(&timeZoneOffset) {
                    let hours = timeZoneOffset / 100
                    let minutes = timeZoneOffset % 100
                    // Adjust timestamp according to timezone:
                    timeStamp += NSTimeInterval(3600 * hours + 60 * minutes)
                }

                // Check suffix:
                if scanner.scanString(suffix, intoString: nil) {
                    // Success! Create NSDate and return.
                    self.init(timeIntervalSince1970: timeStamp)
                    return
                }
            }
        }

        // Wrong format, return nil. (The compiler requires us to
        // do an initialization first.)
        self.init(timeIntervalSince1970: 0)
        return nil
    }
}

使用的例子如下:

if let theDate = NSDate(jsonDate: "/Date(1427909016000-0800)/")
{
    println(theDate)
}
else
{
    println("wrong format")
}

NSDateFormatter:格式化时间

var dataString = "April 1, 2015" as String
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
dateFormatter.timeZone = NSTimeZone.localTimeZone()

// convert string into date
let dateValue = dateFormatter.dateFromString(dataString) as NSDate!

println(dateValue)

NSCalendar

// Playground - noun: a place where people can play

import UIKit

// Setup the calendar object
let calendar = NSCalendar.currentCalendar()

// Set up date object
let date = NSDate()

// Create an NSDate for the first and last day of the month
//let components = calendar.components(NSCalendarUnit.CalendarUnitYear |
//                                     NSCalendarUnit.CalendarUnitMonth |
//                                     NSCalendarUnit.WeekdayCalendarUnit |
//                                     NSCalendarUnit.WeekCalendarUnit |
//                                     NSCalendarUnit.CalendarUnitDay,
//                                     fromDate: date)

// Create an NSDate for the first and last day of the month
let components = NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitMonth, fromDate: date)


components.month

// Getting the First and Last date of the month
components.day = 1
let firstDateOfMonth: NSDate = calendar.dateFromComponents(components)!

components.month  += 1
components.day     = 0
let lastDateOfMonth: NSDate = calendar.dateFromComponents(components)!

var unitFlags = NSCalendarUnit.WeekOfMonthCalendarUnit |
                NSCalendarUnit.WeekdayCalendarUnit     |
                NSCalendarUnit.CalendarUnitDay

let firstDateComponents = calendar.components(unitFlags, fromDate: firstDateOfMonth)
let lastDateComponents  = calendar.components(unitFlags, fromDate: lastDateOfMonth)

// Sun = 1, Sat = 7
let firstWeek = firstDateComponents.weekOfMonth
let lastWeek  = lastDateComponents.weekOfMonth

let numOfDatesToPrepend = firstDateComponents.weekday - 1
let numOfDatesToAppend  = 7 - lastDateComponents.weekday + (6 - lastDateComponents.weekOfMonth) * 7

let startDate: NSDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: -numOfDatesToPrepend, toDate: firstDateOfMonth, options: nil)!
let endDate:   NSDate = calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: numOfDatesToAppend, toDate: lastDateOfMonth, options: nil)!

Array(map(0..<42) {
    calendar.dateByAddingUnit(NSCalendarUnit.CalendarUnitDay, value: $0, toDate: startDate, options: nil)!
})

"\(components.year)"


var dateString = "2014-10-3" // change to your date format
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"

var someDate = dateFormatter.dateFromString(dateString)
println(someDate)

字符串

  let string1 : String = "Hello"
     let string2 : String = "Hel" + "lo"
     if string1 == string2 {
         println("The strings are equal")
  }

创建增删

字符串插值

Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当做占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:

println("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出 "The current value of friendlyWelcome is Bonjour!

索引遍历

存在判断

 if string1.hasPrefix("H") {
         println("String begins with an H")
 }
if string1.hasSuffix("llo") {
         println("String ends in 'llo'")
}

类型编码

编解码

let stringToConvert = "Hello, Swift"
let data = stringToConvert.dataUsingEncoding(NSUTF8StringEncoding)

Indexed Collections

数组(Array)

var arrayOfIntegers : [Int] = [1,2,3]
// 隐式指定
var implicitArrayOfIntegers = [1,2,3]

// 也可以创建空数组,但必须提供其类型
let anotherArray = [Int]()

//使用 append 函数向数组的末尾追加对象
myArray.append(4)

//数组中的任意位置插入对象
myArray.insert(5, atIndex: 0)

元组(Tuples)

元组(tuples)把多个值组合成一个复合值。元组内的值可以使任意类型,并不要求是相同类型。下面这个例子中,(404, “Not Found”)是一个描述 HTTP 状态码(HTTP status code)的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个 404 Not Found 状态码。

let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")

(404, “Not Found”)元组把一个 Int 值和一个 String 值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为(Int, String)的元组”。你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。只要你想,你可以创建一个类型为(Int, Int, Int)或者(String, Bool)或者其他任何你想要的组合的元组。

你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:

let (statusCode, statusMessage) = http404Error
println("The status code is \(statusCode)")
// 输出 "The status code is 404"
println("The status message is \(statusMessage)")
// 输出 "The status message is Not Found"

如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(_)标记:

let (justTheStatusCode, _) = http404Error
println("The status code is \(justTheStatusCode)")
// 输出 "The status code is 404"

索引遍历

你还可以通过下标来访问元组中的单个元素,下标从零开始:

println("The status code is \(http404Error.0)")
// 输出 "The status code is 404"
println("The status message is \(http404Error.1)")
// 输出 "The status message is Not Found"

你可以在定义元组的时候给单个元素命名:

let http200Status = (statusCode: 200, description: "OK")

给元组中的元素命名后,你可以通过名字来获取这些元素的值:

println("The status code is \(http200Status.statusCode)")
// 输出 "The status code is 200"
println("The status message is \(http200Status.description)")
// 输出 "The status message is OK"

作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个(Int, String)元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值(06_Functions.html#Function_Parameters_and_Return_Values)。注意:元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考类和结构体。

序列操作

Swift 增加了一些方法,帮助我们对集合进行简洁的查询和修改。这些集合方法受到了函数式语言的启发。我们使用集合将多个值保存到一个单独的数据结构中,通常我们也会查询和修改集合。这些函数是基于 Swift 的标准数据库构建,协助简化常见的任务。为了协助诠释下面这些函数,我们使用了这些样例:

let ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。

对集合中的每个值执行闭包映射(map),之后返回填充有映射值的映射结果类型数组。下面我们将 Int 数组转化为字符串数据:

    let strings = ints.map { return String($0) }

    print("strings: \(strings)") // prints: strings: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

对数组中的每个值执行函数筛选(filter),返回 Bool 值。在结果数组中,只会返回 true 值,而不会返回 false 值。下面我们从 ints 数组中筛选奇数:

    let evenInts = ints.filter { return ($0 % 2 == 0) }

    print("evenInts: \(evenInts)") // prints: evenInts: [0, 2, 4, 6, 8]

reduce 比 map 和 filter 更复杂,不过因为非常有用,花时间学习也是有价值的。第一个参数就是第一个 reduce 值(在下面的案例中为 0)。第二个参数是访问之前 reduce 值和数组现值的函数。在本例中,我们的函数是将之前的函数值简单加到数组的现值中。

    let reducedInts = ints.reduce(0, combine: +)

    print("reducedInts: \(reducedInts)") // prints: reducedInts: 45


    // defined another way:


    let reducedIntsAlt = ints.reduce(0) { (previousValue: Int, currentValue: Int) -> Int in

        return previousValue + currentValue

    }

    print("reducedIntsAlt: \(reducedIntsAlt)") // prints: reducedIntsAlt: 45

通过 map,filter,reduce 方面的技巧,就能减少筛选时和处理集合时的工作量,并增加可读性,方便以后的人维护。

Keyed Collections

字典

字典是一种将键映射到值的类型,类似 Java 的 Map,PHP 的数组

 var crew = [
          "Caption": "Jean-Luc Picard",
          "First officer": "William Riker",
          "Second Officer": "Data"
];


crew["Captain"]
// = "Jean-Luc Picard"
上一页
下一页