美文网首页ios 开发Swift开发iOS
Swift十二讲 第三章 数组字典函数和闭包 (draft)

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

作者: zydscience | 来源:发表于2015-01-31 12:16 被阅读1184次

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

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

    相关文章

      网友评论

        本文标题:Swift十二讲 第三章 数组字典函数和闭包 (draft)

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