回到首页

输入关键词,多个关键词用空格分隔。

← 编程语言与英语 · 系列目录

Swift2 学习笔记 1 - 概述

约 8 分钟
本页目录

这一章主要是通过一些实际的代码让大家对 Swift 有一个初步的感觉,具体的语法以及技术细节会在之后的章节中详细介绍。


简单值

  • 使用 let 来声明常量
  • 使用 var 来声明变量
  • 大部分情况下不用明确声明类型
  • 显式声明的话,用冒号分割 let explicitDouble: Double = 70
  • 值永远不会被隐式转换成其他类型,需要时请显式转换
  • 一个简单的值转字符串的方法是把值写到括号中,并且在括号前加一个反斜杠,括号中可以是一个表达式
  • 使用方括号来创建数组和字典,用下标或者 key 来访问元素,最后一个元素后面允许有逗号
  • 创建空数组或者字典要用初始化语法
// variable and constant value
var myVariable = 42
myVariable = 50
let myConstant = 33

// explicit declare
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70

// cast type
let label = "The width is"
let width = 94
let widthLabel = label + String(width)

// easy cast from value to string
let apples = 3
let appleSummary = "I have \(apples) apples."  

// array
var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"

// dict
var occupations = ["Da": "Captain", "Wang": "Warrior",]
occupations["WDX"] = "Hero"

// init empty array / dict
let emptyArray = [String]()
let emptyDict = [String: Float]()

控制流

  • 条件操作 if 和 switch
  • 循环操作 for-in, for, while 和 repeat-while
  • 包裹条件和循环变量的括号可以省略,但是语句体必须要大括号
// for loop with if-else statment
let Scores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in Scores{
	if score > 50 {
		teamScore += 3
	} else {
		teamScore += 1
	}
}
print(teamScore)

可以使用 if 和 let 来处理值缺失的情况。这些值可由可选值来代表。一个可选的值是一个具体的值或者是 nil 以表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。在下面的例子中,如果变量的可选值是 nil,条件会被判断为 false,大括号中的代码会被跳过

var optionalString: String? = "Hello"
print(optionalString == nil)

var optionalName: String? = "Da Wang"
var greeting = "Hello!"
if let name = optionalName {
	greeting = "Hello, \(name)"
}

另一种方法是通过 ?? 操作符来提供一个默认值。如果可选值缺失,用默认值代替

let nickName: String? = nil
let fullName: String = "Da Wang"
let greeting = "Hi \(nickName ?? fullName)"

switch 支持任意类型的数据以及各种比较操作,而且不需要写 break,执行完子句会自动退出

let vegetable = "cucumber"
swtich vegetable{
	case "carrot":
		print("Oh Carrot!")
	case "cucumber":
		print("Oh Cucumber!")
	case let x where x.hasSuffix("pepper"):
		print("Oh Special One!")
	default:
		print("Nothing happened")
}

可以使用 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
		}
	}
}
print(largest)

使用 while 来重复运行一段代码直到不满足条件,循环条件也可以在末尾,保证至少循环一次

// while loop
var n = 2
while n < 100 {
	n = n * 2
}
print(n)

// repeat while loop
var m = 2
repeat {
	m = m * 2
} while m < 100
print(m)

也可以在循环中使用 ..< 来表示范围,注意 ..< 创建的范围不包含上界,如果要包含的话,使用 ...

var forLoop = 0
for i in 0..<4 {
	forLoop += i
}
print(forLoop)

forLoop = 0
for i in 0...4 {
	forLoop += i
}
print(forLoop)

函数和闭包

使用 func 来声明一个函数,使用名字和参数来调用函数。使用 -> 来指定函数返回值的类型

func greet(name: String, day: String) -> String {
	return "Hello \(name), today is \(day)"
}

greet("Da", day: "Friday")

使用元组来让一个函数返回多个值。该元组的元素可以用名称或数字来表示

func calStats(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 stats = calStats([5, 3, 100, 2, 9])
print(stats.sum)
print(stats.2)

函数可以带可变个数的参数,这些参数在函数内表现为数组的形式

func sumOf(numbers: Int...) -> Int {
	var sum = 0
	for number in numbers {
		sum += number
	}
	return sum
}

sumOf()
sumOf(42, 583, 12)

函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,可以用来重构一个太长或者太复杂的函数

func returnFifteen() -> Int {
	var y = 10
	func add() {
		y += 5
	}
	add()
	return y
}

returnFiftee()

函数是第一等类型,也就是说,函数可以作为另一个函数的返回值

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 lessThenTen(number: Int) -> Bool {
	return number < 10
}

var numbers = [20, 19, 7, 12]
hasAnyMatches(numbers, condition: lessThanTen)

函数实际上是一种特殊的闭包:它是一段能之后被调取的代码。比保重的代码能访问闭包所建作用域中能得到的变量和函数,即使闭包是在一个不同的作用域被执行的

numbers.map({(number: Int) -> Int in let result = 3 * number return result})

如果一个闭包的类型已知,,可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当作结果返回

let mappedNumbers = numbers.map({number in 3 * number })
print(mappedNumbers)

也可以通过参数位置而不是参数名字来引用参数。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数时,可以完全忽略括号

let sortedNumbers = numbers.sort { $0 > $1}
print(sortedNumbers)

对象和类

使用 class 和类名来创建一个类,其他的语法和前面说的一致。

  • 使用 init 来初始化一个构造器
  • 使用 deinit 来创建一个析构函数
class Shape {
	var numberOfSides: Int = 0
	var name: String
	
	init(name: String){
		self.name = name
	}
	
	func simpleDescription() -> String {
		return "A shape with \(numberOfSides) sides."
	}
}

要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

子类的定义方法实在它们的类名后面加上父类的名字,用冒号分割。如果要重写父类的方法,需要用 override 标记,否则会报错,编译器同样会检测 override 标记的方法是否确实在父类中

class Square: Shape {
	var sideLength: Double
	
	init(sideLength: Double, name: String) {
		self.sideLength = sideLength
		super.init(name: name)
		numberOfSides = 4
	}
	
	func area() -> Double {
		return sideLength * sideLength
	}
	
	override func simpleDescription() -> String {
		return "A square with sides of length \(sideLength)."
	}
	
	let test = Square(sideLength: 5.2, name: "my test square")
	test.area()
	test.simpleDescription()
}

除了储存简单的属性之外,属性可以有 getter 和 setter

class EquilateralTriangle: Shape {
	var sideLength: Double = 0.0
	
	init(sideLength: Double, name: String){
		self.sideLength = sideLength
		super.init(name: name)
		numberOfSides = 3
	}
	
	var perimeter: Double {
		get {
			return 3.0 * sideLength
		}
		set {
			sideLength = newValue / 3.0
		}
	}
	
	override func simpleDescription() -> String {
		return "An equilateral triangle with sides of length \(sideLength)."
	}
}

var triangle = EquilateralTriangle(sideLength: 3.1, name: "a tragnle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)

如果不需要计算属性,但是仍然需要在设置一个新值之前或者之后运行代码,使用 willSet 和 didSet

枚举和结构体

使用 enum 来创建一个枚举,枚举也可以包含方法

enum Rank: Int{
	case Ace = 1
	case Two, Three, FOur, Five, Six, Seven, Eight, Nine, Ten
	case Jack, Queen, King
	func simpleDescription() -> String {
		switch self{
			case .Ace:
				return "ace"
			case .Jack:
				return "jack"
			case .Queen:
				return "queen"
			case .King:
				return "king"
			default:
				return String(self.rawValue)
		}
	}
}

let ace = Rank.Ace
let aceRawValue = ace.rawValue

枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,以防原始值没有意义,我们不需要设置。

使用 struct 来创建一个结构体。结构体和类最大的区别是结构体是传值,类是传引用。

struct Card {
	var rank: Rank
	func simpleDescription() -> String {
		return "The \(rank.simpleDescription())"
	}
}

协议和扩展

使用 protocol 来声明一个协议,类、枚举和结构体都可以实现协议,在结构体中 mutating 关键字用来标记一个会修改结构体的方法

protocol ExampleProtocal {
	var simpleDescription: String { get }
	mutating func adjust()
}

// class
class simpleClass: ExampleProtocol {
	var simpleDescription: String = "A very simple class."
	var anotherProperty: Int = 15213
	func adjust() {
		simpleDescription += "  Now 100% adjusted"
	}
}

// struct
struct Simple Structure: ExampleProtocol {
	var simpleDescription: String = "A simple strucure"
	mutating func adjust() {
		simpleDescription += " (adjusted)"
	}
}

使用 extension 来为现有的类型添加功能

extension Int: ExampleProtocol {
	var simpleDescription: String {
		return "The number \(self)"
	}
	mutating func adjust() {
		self += 42
	}
}

print (7.simpleDescription)

泛型

在尖括号里写一个名字来创建一个泛型函数或者类型

func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item]{
	var result = [Item]()
	for _ in 0..<numberOfTimes{
		result.append(item)
	}
	return result
}

repeatItem("knock", numberOfTimes: 4)

在类型名后面使用 where 来指定对类型的需求,比如,限定类型实现某一个协议,限定两个类型是相同的,或者限定某个类必须有一个特定的父类。

func anyCommonElements <T: SequenceType, U: SequenceType where T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, _ rhs: U) -> Bool){
	...
}

相关文章