一个 C++ 程序员眼中的 Swift(二)

作为学习笔记,这一系列的内容会显得非常琐碎。这正如海边的贝壳,虽然大小不一,但各有特色,每一个都让你欣喜不已,爱不释手。也正因为是在学习过程中的一些零星记录,所以内容会浅显很多,并且缺乏严谨,甚至会出现谬误。这是需要注意的。

  1. 元组

    元组最常用的场景应该就是函数需要返回多个值的情况了。我们再也不需要把多个返回值通过指针或引用参数传递回去了。

    let (status, description) = httpRequest("http://cbug.org")
    

    Swift 的元组还有很多有意思的用法。

    let httpStatus = (404, "Not Found")
    println("The status code is \(httpStatus.0) and the status message is \(httpStatus.1)")
    
    let (code, message) = httpStatus
    println("The status code is \(code) and the status message is \(message)")
    
    let http200Status = (code:200, message:"OK")
    println("The status code is \(http200Status.code) and the status message is \(http200Status.message)")
    
  2. 可选类型

    想象一下这么一个要求:写一个函数返回你最喜欢的数字。这不难:

    int myFavoriteNumber();
    

    这看起来很简单,但如果我没有喜欢的数字呢?这个函数该返回什么?C/C++ 似乎没有一种类型可以表示『根本没有值』这个概念。可能你会想到 NULL。但 NULL 只能指示指针。Objective-C 里有个 nil,和 NULL 差不多,都对基本类型无能为力。

    所以,Swift 发明了一种『可选类型』,它表示『这有个值是什么』或者『这根本没有值』。上面的函数用 Swift 是可以这么写:

    func myFavoriteNumber() -> Int? {
       //...
    }
    
    if let fav = myFavoriteNumber() {
       println("My favorite number is \(fav).")
    } else {
       println("I have no favorite number.")
    }
    

    可选类型是迄今为止我所知的 Swift 中最不可思议的特性了。

  3. 赋值运算符本身不返回任何值

    在 C/C++ 中经常犯的一个错误就是把 == 写成 =。这在以前,最牛的程序员也得花半天时间去 debug 由此引起的各种诡异的情况。直到各个集成开发环境及编译器对这种『错误』给出警告,才逐渐缓解。

    Swift 做的更彻底。赋值运算符不返回任何值,所以在一个期望布尔值(或其他任何值)的上下文里写 = 是直接给出编译错误的。

    if x = y { // Error!
       //...
    }
    

    同样的还有各种组合赋值运算符:+=-=*=等。

  4. 恒等运算符

    Swift 增加了两个比较运算符 ===!== 来比较两个对象是否是引用的相同实例。

  5. 区间运算符

    Swift 的区间运算符可以很方便的创建出一个递增的整数数组,配合 for-in 语句可以很方便地进行迭代。

    区间运算符包括闭区间运算符 a...b 和 开区间元算符 a..<b 两种。它们的区别是前者包含 b 后者不包含。

    let names = ["xiaoming", "xiaohong"]
    for i in 0..<names.count {
      println("I'm \(names[i]).")
    }
    
  6. String 是值类型

    这一点其实是和 C++ 的 std::string 是一样的。但不同于 Objective-C 的 NSString似乎 Objective-C 中的大部分对象都是引用对象)。

    值类型的一个好处就是,『是你的就是你的』。而在用引用对象的时候却要时刻担心这个对象会不会被其他拥有这个对象的引用的人修改。

    Swift 中的 String 虽然是值类型,但经过了优化,只有在必须拷贝的情况下才进行拷贝,所以,效率会很高,可以放心使用。

  7. 字符类型 Character

    Swift 的字符类型天生就支持 Unicode。在支持 emoji 的环境里,你可以把一个表情符直接赋值给一个字符型变量或常量。并且字面字符和字符串一样是使用的双引号,而不是 C/C++ 中使用单引号表示字符,使用双引号表示字符串。当然,这也有个缺点就是不能使用 Swift 的类型推断而省掉 Character 声明了。

    let dog: Character = "🐶" // Mac 下 Chrome 似乎不能正常显示
    

    另外,字符类型对 Unicode 的扩展字符集的支持很有意思。详细内容还是查看《The Swift Programming Language》的『Extended Grapheme Clusters』小节吧。

  8. 正因为字符串对 Unicode 的支持,不能开心的算字符串长度了

    因为不同的字符以及相同的字符的不同表示所占用的内存空间不同,所以,在计算一个字符串中含有的字符个数时,需要从头到位扫描以便字符串。

  9. 集合类型

    在 C++ 中,std::liststd::vectorstd::map 等都只能同时存储同一类型的变量。因为 Objective-C 中使用了引用,所以 NSArrayNSDictionary 等是可以存储任意类型的变量的。

    在 Swift 中,采用了和 C++ 相同的策略,即同时只能存储同一类型的变量。

  10. 数组支持区间运算符

    var numbers = [1, 2, 3, 4, 5, 6, 7]
    numbers[2...5] = [8, 9]
    // numbers is now [1, 2, 8, 9, 7]
    
  11. 未完待续

Creative Commons License Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 4.0 International license .