最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记。
Swift和Objective-C相比,在语法和书写形式上做了很多改进,面向开发者的体验更好了。比如:
println("Hello, world!")
就可以打印出这个字符串,这条语句就是完整的一句,句末不需要添加分号,也不需要引入额外的头或者库文件比如标准输入输出等。在全局作用域内书写的代码就会作为程序的入口,因此不需要编写main函数了。
简单值
用let声明常量,用var声明变量。常量的值在编译的时候不需要知道,但是必须在某个地方真正给它赋值一次,因此常量通常是在一个地方声明和赋值,在很多地方使用的。
var myVariable = 42 myVariable = 50 let myConstant = 42
常量和变量的类型必须和所赋的值保持一致。但是,并不用每次都显示地写明变量类型,可以只给它们提供值,而让编译器去推测它们的类型。上面的例子就是这样的,也可以显示地写明类型:
let explicitDouble: Double = 70
变量不会隐式地进行类型转换,如果需要类型转换,必须要开发者显示地进行,比如:
let label = "The width is " let width = 94 let widthLabel = label + String(width)
在字符串中引用变量还有更简单的方式,就是直接用反斜杠加上圆括号就可以了,比如:
let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit."
创建数组和字典是用中括号,获取数组或字典的值也是。
var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations"
创建空数组或空字典时,用初始化语法更为简便:
let emptyArray = [String]() let emptyDictionary = [String: Float]()
如果元素类型能够被推理出来,甚至可以省略类型声明,用[]表示空数组,[:]表示空字典,比如:
shoppingList = [] occupations = [:]
控制流
用if和switch做条件选择,用for-in,for,while,do-while做循环,选择条件的圆括号和循环变量是可以省略的,但是主体部分的大括号不能省略:
let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } println(teamScore)
在if结构中,条件语句的值必须是一个Boolean表达式,这就使得上面的例子中if score {。。。}无法通过,而不是将score值隐式地转换了。
if和let可以结合使用,这样可以避免找不到该变量。这种变量相当于可省略的,可省略的变量要么等于某个值,要么就是nil(未找到该变量),在变量类型之后加上一个?来标明该变量是可省略的:
var optionalString: String? = "Hello" println(optionalString == nil) var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }
switch支持任何数据类型以及很多种条件比较表达式(并不限定为整数或者判断是否相等):
let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": let vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment = "Is it a spicy \(x)?" default: let vegetableComment = "Everything tastes good in soup." }//Is it a spicy red pepper?
default分支是必须的,否则编译会报错。
注意是如何用let将满足一个表达式的值赋给一个常量的。
在进入合适的case之后,程序会跳出switch块,忽略其他case,因此不需要在每个case最后都加上break;
用for in来遍历数组或字典,数组是按顺序排列的,而字典则是随机排列的键值对。
let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25], ] var largest = 0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } println(largest)
white和do-while用来做循环:
var n = 2 while n < 100 { n = n * 2 } println(n) var m = 2 do { m = m * 2 } while m < 100 println(m)
当然,在循环体中可以引用当前的index,要么用..<来创建index的范围,或者显示地声明初始值,条件语句和递增量,这两种方法是完全等价的:
var firstForLoop = 0 for i in 0..<4 { firstForLoop += i } println(firstForLoop) var secondForLoop = 0 for var i = 0; i < 4; ++i { secondForLoop += i } println(secondForLoop)
..<不包含范围的最大值,而...包含范围的最大值和最小值
函数和闭包
用func来声明函数,用->来标明函数的返回值:
func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday")
用元组来构建复合值。比如,从一个函数返回多个值。元组的元素可以用名称或者数字索引:
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) { var min = scores[0] var max = scores[0] var sum = 0 for score in scores { if score > max { max = score } else if score < min { min = score } sum += score } return (min, max, sum) } let statistics = calculateStatistics([5, 3, 100, 3, 9]) println(statistics.sum) println(statistics.2)
函数也可以接受不定个数的变量,把它们全部包含进一个数组,比如:
func sumOf(numbers: Int...) -> Int { var sum = 0 for number in numbers { sum += number } return sum } sumOf() sumOf(42, 597, 12)
函数是可以嵌套的,内部函数可以访问外部函数的变量(JS中的闭包)
func returnFifteen() -> Int { var y = 10 func add() { y += 5 } add() return y } returnFifteen()
函数本身也可以作为返回值被外部函数返回或者作为参数被传递:
func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() increment(7)
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool { for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int) -> Bool { return number < 10 } var numbers = [20, 19, 7, 12] hasAnyMatches(numbers, lessThanTen)
函数其实是闭包的一种特殊情况而已:就是可以在程序的其他地方被调用的代码块。闭包里的代码可以访问闭包被创建时所在的作用域链上的变量或者函数,不管闭包在执行的时候是在哪个作用域,嵌套函数就很好地说明这个问题了。
编写匿名闭包可以通过将代码包含在大括号里边,用in将参数序列及返回值和函数体分开:
numbers.map({ (number: Int) -> Int in let result = 3 * number return result })
闭包可以写得更简洁,如果闭包的类型是已知的,比如某个代理的回调,则可以省略它的参数类型和返回值类型。
let mappedNumbers = numbers.map({ number in 3 * number }) println(mappedNumbers)
变量的引用也可以用数字而非名字,这在短闭包中非常有用。被作为最后一个参数传递给函数的闭包可以直接在圆括号之后出现:
let sortedNumbers = sorted(numbers) { $0 > $1 } println(sortedNumbers)
这一篇就到这里吧,接下来就要接触到类相关的语法了。