您的位置:首页 > 移动开发 > Swift

The Swift Programming Language中文版 ----A Swift Tour (一)

2014-06-03 15:53 507 查看
第一部分Welcome to Swift 第二章:A Swift Tour

因为英文文档各位看官手里都有。所以我这里就不在占用篇幅来粘贴英文文档了。直接上译文:

Swift 概述

在编程传统中,第一个程序是在屏幕上打印一句“Hello World”。在Swift中,这句话可以使用一句话来完成:

如果你使用过C或者OC语言来编写代码。那么看起来这个语法你很熟悉。在Swift中,这行代码是一个完整的程序。你并不需要为输入/输出或者字符串处理功能来导入一个单独的库。写在全球范围的代码都作为函数的入口点,所以你并不需要一个main函数,也不必在每个语句的末尾写分号。

这次概览通过展示如何完成各种程序任务来给你足够的信息开始编写Swift代码,如果你有不明白的地方,不要担心,这个概览里的一切细节都会在本书后面进行详细解释。

注:为获得最佳体验,在Xcode里把本章作为一个playground打开,playground允许你编辑代码清单,并立即看到结果。

1.简单值

使用let 来创建一个常量,使用var来创建一个变量。一个常量的值并不需要在编译时是已知的,但你必须给它分配一个值一次,这意味着你可以使用常量来命名一个你决定在许多地方使用的值。

var myVariable = 42
myVariable = 50
let myConstant = 42


常量或变量必须有相同的类型,你要分配给它的值。然而,你并不总是必须明确写出类型。提供一个值,当您创建一个常量或变量可以让编译器推断出其类型。在上面的示例中,编译器推断出myVariable是整数,因为它的初始值是一个整数。

如果初始值没有提供足够的信息(或者如果没有初始值),可以在改变后制定类型,用冒号隔开。

let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70


尝试:创建一个常数,明确为float类型,并且值为4

值永远不会转换为另一种类型。如果你需要一个值转换为不同的类型,明确地创建一个所需类型的实例。

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


尝试:尝试从最后一行除去String的转换,你得到了什么错误?

还有一个更简单的方法包含字符串值:把值写在括号中 ,并在括号前写一个反斜线(\)。例如:

let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit.


尝试:使用(\),在一个string里包含一个浮点计算,并在一个greeting里包含某个人的名字。

使用方括号([])创建数组和字典,并在括号中写出index和key来访问它们的元素。

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 = Dictionary<String, Float>()


如果类型信息可以推断,你可以写一个空数组为[]和一个空字典为[;] 。例如,当你设置一个变量的新值或参数传递给函数。

shoppingList = []   // Went shopping and bought everything.


2.控制流

使用 if 和 swith 来书写条件语句。使用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
}
}
teamScore


在 if 的声明时, 条件必须是一个布尔表达式。这意味着if score { ... }是一个错误的语句。

结合if和let,可以方便的处理可空变量(nullable variable)。对于空值,需要在类型声明后添加?显式标明该类型可空。

var optionalString: String? = "Hello"
optionalString == nil

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
尝试:将optinalName设为nil,greeting的值将会怎样?添加一个else,当optinalName为nil时为greeting设置一个不同的值。

如果if语句可选的值为nil时,条件控制将为false,括号中的代码也将被跳过。否则,可选的值将会在常量let后分配给该常量。

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."
}


尝试:删掉default case,将会出现什么错误?

执行了相对应的swith
case中的方法后,程序会从swith中退出,并不会执行下一个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
}
}
}
largest


尝试:添加一个变量,用于跟踪哪个数是最大的,以及数量最多的数是哪个。

使用while来完成重复的代码块,直到条件变化时才会跳出while。循环的条件判断放在循环末端,这样可以保证循环体内的代码至少运行一次。

var n = 2
while n < 100 {
n = n * 2
}
n

var m = 2
do {
m = m * 2
} while m < 100
m


除了传统的for循环之外,也可以通过结合..(生成一个区间)和for-in实现同样的逻辑。

var firstForLoop = 0
for i in 0..3 {
firstForLoop += i
}
firstForLoop

var secondForLoop = 0
for var i = 0; i < 3; ++i {
secondForLoop += 1
}
secondForLoop


使用..确定一个范围并忽略它的上限值,同时也可以使用..来确定一个范围,并包含这两个值。

3.函数和闭包

使用func来定义一个函数,按照其名称和括号内的参数列表来调用该函数,使用->来定义函数的返回值类型和名称。

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


尝试:删除 day参数,在greeting中添加一个“今天的午餐”的参数。

使用一个元组来从函数中返回多个值。

func getGasPrices() -> (Double, Double, Double) {
return (3.59, 3.69, 3.79)
}
getGasPrices()


函数也可以返回可变数目的参数,并将他们存放在数组中。

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


尝试:写一个用于计算平均值的函数。

函数可以嵌套。嵌套函数可以访问在外部函数中声明的变量。你可以使用嵌套函数来组织代码中很长很复杂的函数。

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)


函数实际上是闭包的一种特殊情况。您可以通过使用大括号({})周围的代码写一个没有名字的闭包。使用单独的参数和从身体返回类型。

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


尝试:写一个返回所有奇数都为0的闭包。

你可以通过不同的方式让闭包更加简洁,当一个闭包的类型是已知的,如回调委托,可以省略它的参数的类型,它的返回类型,或两者兼而有之。

numbers.map({ number in 3 * number })


闭包的参数可以用数字而不是按引用参数名称 -这样的做法是对很短的闭包特别有用。通过作为最后一个参数传递给函数的闭包可以在括号后立即出现。

sort([1, 5, 3, 12, 2]) { $0 > $1 }


4.对象和类

使用 class 后跟类名来创建一个类。声明类的属性与变量或常量的声明方式相同,只不过它是在thecontext类中。同样,方法和函数的声明方式也相同。

class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}


尝试:使用 let 增加一个常量属性,并添加一个方法来接受一个参数。

通过类名后跟括号来创建类的实例,使用点语法来访问该实例的属性和方法。

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


这个版本的Shape类缺少了一个很重要的东西:在设置初始化时,这个类已经被创建了。应使用init创建。

class NamedShape {
var numberOfSides: Int = 0
var name: String

init(name: String) {
self.name = name
}

func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}


通过init构建对象,既可以使用self显式引用成员字段(name),也可以隐式引用(numberOfSides)。

如果你的对象在被释放之前需要做一些清理工作,那么要使用deinit来创建一个reinitializer。

子类在类名后应包含他们超类的类名。Swift支持继承和多态(override父类方法)。如果这里的simpleDescription方法没有被标识为override,则会引发编译错误。

class Square: NamedShape {
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: NamedShape {
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 triagle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength


在perimeter的setter中,新的值有一个隐藏的名字newValue,你可以在set方法的括号中提供一个名字。

请注意,初始化为EquilateralTriangle类有三个不同的步骤:

1.设置的子类声明的属性的值。

2.调用父类的初始化方法。

3.想要改变父类中定义的属性的值,可以使用除setter或getter方法之外的自定义方法。

如果不需要计算属性的值,但需要在赋值前后进行一些操作的话,使用willSet和didSet:

class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
triangleAndSquare.triangle.sideLength


类中的方法有一个重要区别就是函数,函数的参数名只能在函数中使用,但是当你调用这个方法时,可以使用参数的名称(除了第一个参数),默认情况下,当你调用方法时,它们的参数和方法本身不会改变。在方法内,你可以为它指定第二个名字。

class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)


当与可选值一起工作时,你可以写 "?" 到操作符之前类似于方法属性。如果值在"?"之前就已经是 nil ,所有在 "?" 之后的都会自动忽略,而整个表达式是 nil 。另外,可选值是未包装的,所有 "?" 之后的都作为未包装的值。在两种情况中,整个表达式的值是可选值。

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: