Swift语言学习笔记(1)

基本语法

  • 声明常量用let,声明变量用var,声明函数用func。
    类型修饰采用后置语法,省略时由编译器根据上下文自行推导:
    声明常量和变量时用冒号指示类型,自带初值时类型修饰可省略。
    声明函数时用箭头指示返回类型,有返回值时返回类型不可省略。
     常量变量函数(有返回值)函数(无返回值)
    Swiftlet i = 10
    let i: Int = 10
    var i = 10
    var i: Int = 10
    func f(n: Int) -> Int {return n + 1}func f(n: Int) -> () {}
    func f(n: Int) -> Void {}
    func f(n: Int) {}
    C#const int i = 10;
    readonly int i = 10;
    var i = 10;
    int i = 10;
    int f(int n){return n + 1;}
    int f(int n) => n + 1;
    void f(int n) {}
    C++const auto i = 10;
    const int i = 10;
    constexpr auto i = 10;
    constexpr int i = 10;
    auto i = 10;
    int i = 10;
    int f(int n) {return n + 1;}
    auto f(int n) -> int {return n + 1;}
    auto f(int n) {return n + 1;}
    void f(int n) {}
    auto f(int n) -> void {}
    auto f(int n) {}
  • 字符串插值(string interpolation)的语法形式为 \(表达式)。
     字符串插值
    Swiftlet x = 10, y = 20
    let s = "x=\(x), y=\(y + 1)"
    C#int x = 10, y = 20;
    var s = $"x={x}, y={y + 1}";
  • 关于运算符,Swift语言中有一些新的运算符:封闭区间,半开区间以及身份比较运算符。
    与C语言不同的是,Swift语言中 = += 等赋值运算符不返回值,也不存在递增 ++ 以及递减 -- 运算符。
     封闭区间半开区间
    Swift2...102..<10
    C#Enumerable.Range(2, 9)Enumerable.Range(2, 8)
    JavaIntStream.rangeClosed(2, 10)IntStream.range(2, 10)
     值比较引用比较
    Swifta == ba === b
    C#Object.Equals(a, b)
    a.Equals(b)
    a == b
    Object.ReferenceEquals(a, b)
    a == b
    Javaa.equals(b)a == b
  • 数据结构方面,数组,集合,字典以及元组有特殊语法。
    数组用中括号,集合用中括号加类型修饰,字典用中括号加冒号,元组用小括号。
     数组集合字典元组
    Swiftlet a = [1,2,3]
    var a = [Int]()
    let a: Set = [1,2,3]
    var a = Set<Int>()
    let d = [1:"a", 2:"b"]
    var d = [Int: String]()
    let t = (1, "a")
    Pythona = [1,2,3]
    a = []
    a = set([1,2,3])
    a = set([])
    d = {1:"a", 2:"b"}
    d = {}
    t = (1, "a")
  • 传统流程控制方面,表示分支的有if, guard和switch,
    表示循环的有for-in, while以及repeat-while,
    表示跳转的有continue, break, fallthrough, return和throw。

元组(Tuples)

  • 元组是一种个数有限,类型可相同或也可不同的有序的值的组合,是一种匿名的结构体。
  • 元组类型本身没有名字,但是成员可以有名字。
  • 元组的类型由成员的个数,类型以及顺序决定,成员的名字不影响元组的类型。
  • 访问元组的成员可以通过模式匹配,也可以通过指定成员的序号或名字。
  • 不存在只包含一个成员的元组。
  • 不包含任何成员的元组类型记作 (),该类型与Void同义。
// http404Error的类型是 (Int, String)
let http404Error = (404, "Not Found")
// 通过模式匹配来访问元组的成员
let (statusCode, statusMessage) = http404Error
let (justTheStatusCode, _) = http404Error
// 通过指定成员的序号来访问元组的成员
print("The status code is \(http404Error.0)")
// http200Status的类型编译期为 (statusCode: Int, description: String),运行期为(Int, String)。
let http200Status = (statusCode: 200, description: "OK")
// 通过指定成员的名字来访问元组的成员
print("The status message is \(http200Status.description)")

可选值(Optionals)

  • 可选值:一种可能没有值的可空类型,声明语法为 类型?,拆包(取出可选值中包含的值)语法为 可选值变量!。
  • 隐式拆包可选值(implicitly unwrapped optionals):一种假定总是有值的可空类型,声明语法为 类型!,引用可选值变量自动拆包,无需加!。
  • 可选绑定(optional binding):在if语句中强制拆包的语法形式。
  • 可选链(optional chaining):通过可选值调用其属性,方法的语法形式。
// 可选值
var possibleString: String?
let forcedString: String = possibleString!
if possibleString != nil {}
// 可选绑定
if let definiteString = possibleString {}
// 可选绑定 可选链
if let definiteString = possibleString?.lowercaseString {}
// 隐式拆包可选值
var assumedString: String! = "abc"
let implicitString: String = assumedString
if assumedString != nil {}
// 可选绑定
if let definiteString = assumedString {}

流程控制(Control Flow)

  • while以及repeat-while(由do-while改名而来)循环继承自传统的C语言,for-in循环用于遍历序列。
    // 遍历区间
    for index in 1...5 {}
    for _ in 1..<3 {}
    // 遍历数组
    let names = ["Anna", "Alex", "Brian", "Jack"]
    for name in names {}
    // 遍历字典
    let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
    for (animalName, legCount) in numberOfLegs {}
    // 遍历字符串
    for ch in "Hello".characters {}
    
  • if ... else if ... else结构继承自传统的C语言。
    guard ... else结构用于表达提前退出(early exit)这种惯用法(检测输入,如不符合要求提早退出函数)。
    Swift语言中的switch语句与传统C语言有很大不同:
    缺省情况下不掉入下一个case,可以同时指定多个值,可以匹配区间,可以对元组作模式匹配,也可以为值绑定添加条件过滤。
    在switch语句中break可用于提前退出某个case,也可用于占位。fallthrough则表示有意掉入下一个case。
    break和continue可以带标号。
    // 提前退出
    func greet(person: [String: String]) {
        guard let name = person["name"] else {return}
    }
    // 多值匹配
    let someCharacter: Character = "e"
    switch someCharacter {
    case "a", "e", "i", "o", "u":
        // ...
    default:
        // ...
    }
    // 区间匹配
    let approximateCount = 62
    switch approximateCount {
    case 0:
        // ...
    case 1..<5:
        // ...
    case 5..<12:
        // ...
    case 12..<100:
        // ...
    case 100..<1000:
        // ...
    default:
        // ...
    }
    // 元组匹配
    let somePoint = (1, 1)
    switch somePoint {
    case (0, 0):
        // ...
    case (_, 0):
        // ...
    case (0, _):
        // ...
    case (-2...2, -2...2):
        // ...
    default:
        // ...
    }
    // 值绑定
    let anotherPoint = (2, 0)
    switch anotherPoint {
    case (let x, 0):
        // ...
    case (0, let y):
        // ...
    case let (x, y):
        // ...
    }
    // 条件过滤
    let yetAnotherPoint = (1, -1)
    switch yetAnotherPoint {
    case let (x, y) where x == y:
        // ...
    case let (x, y) where x == -y:
        // ...
    case let (x, y):
        // ...
    }
    

函数(Functions)

  • 函数的参数有实参标签(argument label)和形参名(parameter name)。
    实参标签如果存在(不为下划线时)调用方必须指定,形参名在函数内使用。
    语法形式为 func 函数名(实参标签1 形参名1: 类型1, 实参标签2 形参名2: 类型2 ...)
    缺省形式为 func 函数名(实参标签1兼形参名1: 类型1, 实参标签2兼形参名2: 类型2 ...)
    即参数缺省实参标签与形参名相同。
     缺省形式完整形式最简形式
    被调用方func f(la: Int, lb: Int){
     la ...
     lb ...
    }
    func f(la na: Int, lb nb: Int){
      na ...
      nb ...
    }
    func f(_ na: Int, _ nb: Int){
      na ...
      nb ...
    }
    调用方f(la: 1, lb: 2)f(la: 1, lb: 2)f(1, 2)
  • 函数形参缺省为只读的in参数,函数内部参数不可修改,参数传递方式为传值。
    inout形参加上inout修饰,函数内部参数可修改,修改对调用方可见,参数传递方式为传引用。
    参数传递方式传值传值传引用传引用
    关键字只读in参数(可读可写)in参数out参数inout参数
    Swiftinout
    C#outref
  • 函数的参数可以有缺省值。
  • 函数是一等公民。可以作为函数的参数,也可以成为函数的返回值。
     函数的类型(有返回值)函数的类型(没有返回值)
    Swift(Int, Int) -> Bool(Int, Int) -> Void
    C#Func<int, int, bool>Action<int, int>
    C++function<bool(int, int)>function<void(int, int)>
  • 函数可以嵌套。
  • 变长参数。最多只能有一个。函数内部该参数被视为数组。
     变长参数
    Swiftfunc avg(numbers: Double...) -> Double {}
    C#double Avg(params double[] numbers) {}
    Javadouble avg(double... numbers) {}

闭包(Closures)

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
// 把函数当作闭包
var reversed = names.sorted(by: backwards)
// 闭包表达式(closure expressions)
reversed = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})
// 单行闭包
reversed = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
// 根据上下文推导参数和返回值的类型
reversed = names.sorted(by: { s1, s2 in return s1 > s2 } )
// 单一表达式闭包
reversed = names.sorted(by: { s1, s2 in s1 > s2 } )
// 缩写参数名
reversed = names.sorted(by: { $0 > $1 } )
// 运算符函数
reversed = names.sorted(by: >)
// 尾随闭包(trailing closure)
reversed = names.sorted() { $0 > $1 }
reversed = names.sorted { $0 > $1 }
  • 函数和闭包都是引用类型。
  • 嵌套函数和闭包均可捕获外围常量和变量。
  • 非逃逸闭包(Nonescaping Closures):作为参数被传入某个函数,只在该函数内部执行的闭包。
  • 逃逸闭包(Escaping Closures):作为参数被传入某个函数,但在该函数返回之后才执行的闭包。
  • 自动闭包(Autoclosures):作为参数被传入某个函数,在调用端以表达式的形式出现,在被调用端被自动创建的闭包。
  • 普通的非自动非逃逸闭包不需要参数类型标注。
    非自动逃逸闭包使用 @escaping 标注参数类型。
    自动非逃逸闭包使用 @autoclosure 标注参数类型。
    自动逃逸闭包同时使用 @autoclosure @escaping 标注参数类型。
  • 逃逸闭包的函数体内需要显式引用 self,而非逃逸闭包的函数体内可以隐式引用 self。
// 非逃逸闭包
func someFunctionWithNoescapeClosure(closure: () -> Void) {
    closure()
}
// 逃逸闭包
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
//
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNoescapeClosure { x = 200 }
    }
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // prints "200"
completionHandlers.first?()
print(instance.x) // prints "100"
// 非自动非逃逸闭包
var customersInLine = ["Alex", "Ewa", "Barry", "Daniella"]
func serveCustomer(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serveCustomer(customer: { customersInLine.removeAtIndex(0) } ) // prints "Now serving Alex!"
// 自动非逃逸闭包
func serveCustomer(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
}
serveCustomer(customer: customersInLine.removeAtIndex(0)) // prints "Now serving Ewa!"
// 自动逃逸闭包
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.removeAtIndex(0))
collectCustomerProviders(customersInLine.removeAtIndex(0))
for customerProvider in customerProviders {
    print("Now serving \(customerProvider())!")
}
// prints "Now serving Barry!"
// prints "Now serving Daniella!"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值