Swift十二讲 第三章 数组字典函数和闭包 (draft)

1.数组

  • 数组的定义和一些简单的例子
    数组是同一类型的东西的有序集合。可以有整数数组,也可以有按钮类的数组。只要是同一类型,都可以。数组的元素由其位置来指定。数组的位置是从0开始的。数组可以是常值也可以是变值。分别用let和var来声明。除非是空数组,不然必须初始化。

下面是几个声明数组的例子:

let a = [1,2,3] //整数数组,Swift可以自己推断出来类型
let m=a[0] //m被赋值为a的第一个元素,等于1
var b = ["x","y","z"]
var c = ["xx","yy"]
var d = b + c  
//数组可以做加法。不管数组是什么类型,加起来就是后一个附加于前一个的后面。不同类型的数组则不能相加。
var xx = [String](count: 2, repeatedValue: "x")

数组是值类型。传递的时候不是传递的地址或者索引,而是确实制造了一个拷贝。这点和Objective C的NSArray不同。

  • 数组的内置算法和属性
    数组有很多内置的算法和属性。下面举例说明一些笔者认为最有用的部分。这些内容往往牵涉到闭包(closure)的使用,读者也可以跳过回头再看。
var a = [10,2,3]
println("\(a.sort { $0 < $1})") //输出[2,3,10]
println(a) //输出[2,3,10]; a被改变了
println("\(a.sorted{ $1 < $0})") //输出[10,3,2]
println(a) //sorted不改变原数组,输出还是[2,3,10]

sort算法执行后,原数组被改变。sorted算法执行后,返回一个排过序的数组。但原来的数组不变。

println("\(a.reverse())") //输出[2,3,10],原数组不变。

reverse顾名思义就是生成一个逆序数组。

println("\(a.filter {$0 > 2 })") //输出[3,10],原数组不变

filter返回满足一定条件的数组元素形成的新数组。filter的条件由一个closure定义。

println("\(a.map {$0 > 0 ? -$0 : 1 })")
//输出 [-2,-3,-10]

map返回数组的每个元素被map这个函数操作后的结果。函数由一个closure定义。

println("\(a.reduce(0) {$0 + $1 })")
//输出为15。

reduce返回一个值,这个值由reduce后面的closure给出。上例的意思是求数组所有元素之和。

数组一些有用的属性如下,意思都很直接易懂:

a.first
a.last //数组的第一个和最末一个元素
a.capacity //数组最多可以存多少个元素而无需后台重新分配内存
a.count //数组有多少个元素
a.isEmpty //数组是空的吗?

可以用下面代码替换数组的一部分元素:

a[1...2] = [2,3] //数组的第二第三个元素被替换为[2,3]

可以用下面代码去掉数组的单个指定元素:

a.removeAtIndex(1)
println(a) //数组的第二个元素被去掉。

可以用下面代码确保数组被分配了足够的内存而不用后台重新调动。

a.reserveCapacity(10) // 预定了够放10个元素的内存。

2.字典

字典的类型的形式定义为Dictionary <KeyType:ValueType>。可以简写为[Keytype:ValueType]。字典其实就是两个数组放在一起,第一个数组是索引,第二个是值。因此,第一个数组不能有重复的值。例如下面句子会报错:

let aa = [1:2, 1:3]

Playground会告诉你:
“fatal error: dictionary literal contains duplicate keys”

另外,既然Key和Value都类似于数组,Key的元素必须是同类型的。Value也必须同类型。

字典的初始化可以指定类型,也可以指定一些初始值,然后编译器会做类型推断。例如:

var a = ["狗有几条腿":4,"人有几条腿":2]
var b: [String:String] = ["狗":"白色","兔子":"灰色"]

你还可以不指定初始值,只是给出其最小容量。或者定义一个空字典。

 var c = [String:String]() 
 var d = [String:String] (minimumCapacity:2)

字典的value部分可以用key来索引到:

println(a["狗有几条腿"]!)  //输出为4

可以定义个一个数组,其值为字典的value部分或者key部分。

var ax = [String](a.keys)
println(ax)
var ay = [Int](a.values)
println(ay)
//注意这里必须指定类型;得到的数组的次序未必就是字典的原来顺序。
//字典是以key为索引的,其元素的位置无意义。

字典也有.count,.isEmpty等类似于数组的属性。

3.定义在数组或者字典上的循环

定义在数组上的循环的格式为:

for item in my_Array
{
 //在这里item被当作常量使用。
//第一次进入循环,item的值是my_Array的第一个值,第二次入循环是数组的第二个值。等等。
//item不能被修改。   
}

例如:

var a=["方","圆","三角"]
for i in a
{
    println(i)
}  //依次输出方圆三角

定义在字典上的循环的格式为:

for (key, value) in my_Dict
{
 //在这里(key,value)被当作常量使用。
//第一次进入循环,的值是my_Dict的第一个值,第二次入循环是数组的第二个值。等等。
//(key,value)不能被修改。   
}

你可以直接定义一个定义在字典的keys上的或者values上的循环

    for my_key in my_Dict.keys
    {
    //my_key是常量,不能修改。每次入循环,自动被赋予下一个keys的值
    }

    for my_value in my_Dict.values
    {
    //my_value是常量,不能修改。每次入循环,自动被赋予下一个values的值
    }

4.函数

Swift的函数和闭包定义和用法是非常丰富的。就算是编程专家,也很难一时掌握好。我们要做的是,化繁为简。只重点阐述用起来肯定不会有问题的,强大的有用的那些部分。

  • Swift的函数不需要像C那样,先声明,后定义。直接写函数体,然后调用就行了。写法为:

    func 函数名(外部参数名 内部参数名:类型,...等等更多参数) ->返值的类型
    {
    //函数内部要做的事
    }

调用函数:

函数名(外部参数名:参数值)
  • 如果外部参数名和内部参数名相同,用#然后只写一个名字就好。
    如果函数定义的时候省略外部参数名,那么调用时可以直接写值。如下例子:
var ii=24
func ad3(x:Int)->Int
{return x+30}
println(ad3(ii)) //输出54
  • 外部参数名之前,可以写var/let/inout三选一。如果什么都不写,那这个参数被默认为let,也就是常值。在函数体内部不能被改变。
  • inout 是个指针或者索引。

套用上面模版,一些例子如下:

var i = 32
var ii = 24

func ad1(var # x:Int)->Int{
x = x+5
return x}

let b = ad1(x: ii)
println(b) //输出29 
println(ii)  //输出24

func ad2(inout i:Int)->Int{
i=i+20
return i+20}

var a = ad2(&i)
println(i) //输出52
println(a) //输出72

如上例所示。如果想要在函数体之内改变函数体之外一个变量的值,只能用inout。

  • 函数可以用变长度参数值。变长度参数值类似于数组的用法。例如:
func ad3(x: Int...)->Int
{return x[1]+30}
println(ad3(30,-1)) //输出29
  • 假设我们有一个函数A,它的类型为T。然后我们定义了一个变量,类型为T。那么我们可以把A的函数名赋值给A。你也可以把一个函数当作另一个函数的返回值或者参数。这大略相当于一个更简洁安全的函数指针。函数的名字可以像变量那样传来传去。但传递的只是函数的索引。
    如下例:
func ad1(var # x:Int)->Int{
x = x+5
return x}
func ad4(x: Int, # myFunc: (Int)->Int)->Int
{
println("结果="+"\(myFunc(x))")
return 0
}
//输出 "结果=7"
//函数ad4的一个参数是类型为(int)->int的函数。
//函数ad1符合这个类型,所以可以传进去执行。

5.闭包

这里只简单介绍下闭包。一来因为目前用处并不广泛。二来Swift说不定会改语法或者扩展语法。我建议读者自行试验和写一些常用的闭包,存起来日后用。不要使用没有仔细分析和试验过的闭包。

  • 粗略地来说,闭包可以被看作一个匿名的函数。
    也就是把函数定义的函数名,变量名都去掉。然后加上in关键字表示函数体。闭包通常按如下格式定义:

    {(参数)->返回值 in
    执行什么什么}

例如:

let animals = ["狗", "猫", "兔"]
let myexample = animals.map({
(x: String) -> String in
"\(x)长大了"+"长大了"
})

println(myexample)
//输出为
//[狗长大了长大了, 猫长大了长大了, 兔长大了长大了]
  • 可以看出,闭包的使用是非常符合人的直观思维的。但和传统C类型的计算机语言区别很大。如上述例子。我们想要把一个数组按照一定的规则变换成另一个数组。那就应该把转换规则写清楚就行了。规则怎么写?如上例所示的写法,其实是和传统函数类似的。但是下面这点是非常不同的。

再比如你想把一个数组的每个元素都平方下:

var xx = [1,2,3]
let b = xx.map({$0 * $0})
println(b) //输出[1,4,9]
//是不是像matlab一样简单?
  • 函数和闭包可以多层定义。也就是在一个函数/闭包内可以定义另外一个函数/闭包。内层的函数/闭包可以调用外层出现过的任何变量,也可以调用外层函数/闭包的参数值。

最后关于所谓的函数式编程吐两句槽。Lambda Calculus是丘奇在古代的伟大发明。学会函数式编程,可以增广见闻,或许在某些场合有用,也或许某天函数式编程会成为主流。但这个东西就和学会用对数表算乘法区别不大。并没有特别神秘之处。发明东西难。学会东西容易。切忌因为会个特殊的语法糖,而时时去用这个语法糖来彰显自己的不同之处,那样会造成项目灾难。

(当然,如果你真的发明了一个类似于函数编程之类的东西,别忘了告诉我。)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容