一个下午让你掌握Swift基础 ( 5/9 ) 做判断

简介

这是一个Swift语言教程,基于最新的iOS 9,Xcode 7.3和Swift 2.2,会为你介绍Swift编程非常基础的内容。从电脑如何工作的全程基本原理到语言结构,你会足够了解这门语言,来处理数据和管理代码的行为。

快速链接


做判断

写一个电脑程序的时候,需要能够用不同的剧本告诉电脑该干什么。例如,一个计算器app在用户按加号按钮的时候要做一件事,按减号按钮的时候做另一件事。
在电脑编程领域,这个概念被称作控制流(control flow)。它被这样命名因为程序的流程(flow)由多种方法控制。在这篇文章里,你会学习到在程序里如何做判断,以及通过使用语法来控制流程。

if语句

第一个也是最常用的控制程序流程的方式就是使用if语句(if statement),可以让程序只在某个特定情况是true的时候做一些事。例如,看下面的代码:

if 2 > 1 {
    print("是的,2比1大。")
}

这一个简单的if语句。如果括号里的情况是true,语句就会执行花括号里的代码。如果括号里的情况是false,语句不会执行花括号里的代码。就这么简单!

上面的代码也为你介绍了新语法:print()函数,简单地显示一些东西到屏幕上。在你的playground里,你可以看见上面print()语句的结果,通过点击 View\Debug Area\Show Debug Area

你会看见这样的东西:

点击上面截图上高亮的两个按钮也可以显示debug(排除错误)区域。Xcode有很多方式来完成同样的事情!

你可以扩展一个if语句,提供在情况是false的时候运行的代码。这被称作else子句(clause)。这是一个例子:

let animal = "狐狸"

if animal == "猫" || animal == "狗" {
    print("这个动物是居家宠物。")
} else {
    print("这个动物不是居家宠物。")
}

这里,如果(if)animal等于“猫”或“狗”,然后语句会运行代码的第一块。如果animal既不等于“猫”又不等于“狗”,语句会运行if语句里else里的那部分代码,在debug区域显示如下内容:

这个动物不是居家宠物。

其实使用 if 语句还能做更多事情。有时候你想检测一个情况,然后是另一个情况。这就是else-if语句参演的地方啦。
你可以像这样使用:

let hourOfDay = 12
let timeOfDay: String
if hourOfDay < 6 {
    timeOfDay = "清晨"
} else if hourOfDay < 12 {
    timeOfDay = "上午"
} else if hourOfDay < 17 {
    timeOfDay = "下午"
} else if hourOfDay < 20 {
    timeOfDay = "晚上"
} else if hourOfDay < 24 {
    timeOfDay = "夜深了"
} else {
    timeOfDay = "这他妈不是时间!"
}
print(timeOfDay)

一个接一个的else-if语句来测试多种情况,直到发现一个true情况。它只会执行和第一个true情况相关的代码,无论随后的else-if情况是不是true。换句话说,else-if情况的顺序影响很大!

你可以在末尾加一个else,来处理所有都不是true的情况。else是可选的,如果你不需要它那就不要;在这个例子里你的确需要它,来确保timeOfDay在你输出它的时候有一个有效值。

这个例子里,else-if语句带有一个数字,表示一天中的时间,然后把它转换到一个字符串,表示这个小时属于一天中的哪个部分。采用24小时时间制,语句被按顺序一个一个检查:

  • 第一次检查看看小时是不是小于6。如果是,意味着在清晨。
  • 如果小时不小于6,语句继续执行第一个else-if,检查小时是不是小于12。
  • 然后按顺序,在情况是false的时候,语句检查小时是不是小于17,然后是小于20,然后是小于24。
  • 最后,如果小时数超出范围了,语句察觉到了一个无效情况,然后把这个信息打印到了控制台。

在上面的代码里,hourOfDay常量是12。因此,代码会在屏幕上像下面这样显示:

下午

注意即使hourOfDay < 20和hourOfDay < 24情况也都是true,但语句只执行了输入满足的第一个else-if,当然就是hourOfDay < 17情况啦。

包含变量

If 语句介绍了一个新概念,那就是scope(范围),通过使用花括号来包含变量的一种方式。

让我们看一个例子。想象一下你要计算向顾客收取的费用。

这是你打好的算盘:

你每小时赚25块,最多40小时,此后的每小时都要50块。

使用Swift,你可以这样计算你的费用:

var hoursWorked = 45

var price = 0
if hoursWorked > 40 {
  let hoursOver40 = hoursWorked - 40
  price += hoursOver40 * 50
  hoursWorked -= hoursOver40
}
price += hoursWorked * 25

print(price)

这段代码检查小时数是不是超过40了。如果是,代码计算超过40的小时数,然后用它乘上50块,然后把结果加到价格上。代码然后从工作的总时间里减去超过40小时的部分。把剩下的工作小时乘以25块,然后加到总价上。

在上面的例子里,结果是这样的:
1250

有意思的是 if 语句里面的代码。有一个新常量的声明,hoursOver40,来保存超过40小时的数字。
很明显你可以在if语句里面使用它。但如果你尝试在上面代码的结尾去使用它,会发生什么?

···
print(price)
print(hoursOver40)

这会导致下面的错误:

`error: use of unresolved identifier 'hoursOver40'(错误:使用了不确定的标识符‘hoursOver40’)`

这个错误告诉你,你只被允许在创建 hoursOver40 常量的 scope 里使用它。这个例子里,if 语句引入了一个新 scope,所以当这个 scope 结束了,你就不能再使用这个常量了。

但是,每个 scope 可以使用来自它的父 scope 的变量和常量。在上面的例子里,if 语句里面的scope使用了 price 和 hoursWorked 变量,他们就是在父 scope 被创建的。

三目操作符(The ternary conditional operator)

现在我想介绍一个新的操作符,你在第三篇文章里没有看到的。叫做三目操作符(The ternary conditional operator),它是和 if 语句相关的。

如果你想判断两个变量最小的值和最小的值,你可以像这样使用if语句:

let a = 5
let b = 10

let min: Int
if a < b {
    min = a
} else {
    min = b 
}

let max: Int
if a > b {
    max = a 
} else {
    max = b 
}

现在你知道这是怎么工作的了,但这有好多代码。如果你能把它缩短到就几行岂不是很好?唔,你可以的,感谢三目操作符!

三目操作符带有一个情况,返回两个值其中之一,取决于那个情况是true还是false。语法如下所示:

 (<情况>) ? <TRUE值> : <FALSE值>

你可以使用这个操作符来重写上面的长代码块,像这样:

let a = 5
let b = 10

let min = a < b ?  a : b
let max = a > b ? a : b

第一个例子里,情况是a<b。如果是true,赋值回min的结果会是a;如果是false,结果会是b的值。

我相信你也同意这样简单多了!这是一个有用的操作符,你会发现自己经常使用它。

**注意:**因为找两个数字中更大的或更小的那个是如此常用的操作,Swift标准库为这个目标提供了两个函数:max和min。

迷你练习

创建一个叫做myAge的常量,初始化为你的年龄。写一个if语句,如果你的年龄在13到19之间,就print“青少年”,如果不是,就print“不是青少年”。

Swift语句

控制流程的另一种方式是使用 switch 语句,允许你根据变量或常量的值来执行不同的代码。

这是一个非常简单的基于整数的 switch 语句:

let number = 10
switch (number) {
case 0:
    print("零")
default:
    print("非零")
}

这个例子,代码会如下输出:

非零

这个switch语句的作用是判断数字是不是零。但它可以做更复杂一点的事!

要处理一个特殊情况,使用 case 后面跟着你想判断的值,这个例子里是0。然后,用default来表明,如果是所有其它值应该做点什么。

这是另一个例子:

let number = 10
switch (number) {
case 10:
    print("这是10!")
default:
    break
}

这次你判断10,在case里print了一条消息。如果是其他值,那什么都不应该发生。当你不想让一个case或default发生任何事情的时候,那就用break关键字。这告诉Swift你不打算在这里写任何代码,任何事都不应该发生。

当然,switch语句也可以处理整数以外的数据类型。他们可以处理任何数据类型!这是一个基于string的例子:

let string = "狗"
switch (string) {
case "猫", "狗":
    print("这个动物是居家型。")
default:
    print("这个动物不是居家型。")
}

这会print如下内容:

这个动物是居家型。

这个例子里,你为case提供了两个值,意味着如果值等于“猫”或“狗”,语句就会执行这个case。

你也可以给switch语句不止一个case。你在这篇文章之前的部分看见了一个 if 语句带有 else-if 从句,可以把一天中的小时转换为描述这是一天中的哪个部分的字符串。你可以用一个switch语句来更简要的重写它,像这样:

let hourOfDay = 12
let timeOfDay: String
switch (hourOfDay) {
case 0, 1, 2, 3, 4, 5:
    timeOfDay = "清晨"
case 6, 7, 8, 9, 10, 11:
    timeOfDay = "上午"
case 12, 13, 14, 15, 16:
    timeOfDay = "下午"
case 17, 18, 19:
    timeOfDay = "晚上"
case 20, 21, 22, 23:
    timeOfDay = "夜深了"
default:
    timeOfDay = "这他妈不是时间!"
}
print(timeOfDay)

代码会 print 如下内容:

下午

如果有多个case,语句会执行第一个满足的case。你应该会同意这个例子比用if语句来的更简要和清晰吧。细节上其实也更严谨,因为 if 语句没法处理负数的情况,但这儿负数被正确地认为是无效的。

基于一个值的property来匹配一个case的情况也是可以的。就像你在第三篇学的,你可以使用模除操作符来判断一个整数是偶数还是奇数。看看这段代码:

let number = 10
switch (number) {
case let x where x % 2 == 0:
    print("偶数")
default:
    print("奇数")
}

这会print如下内容:

偶数

这个switch语句使用了let-where语法,意味着case只会在一个特定情况是true的时候匹配。这个例子里,你设计了case来满足如果值是偶数的情况——那就是值模除2等于0啦。

这个可以基于情况来匹配值的方法叫做模式匹配(pattern matching)

另一种方式使用switch语句也有绝佳效果,像这样:

let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0): // 1
    print("原点")
case (_, 0, 0): // 2
    print("在x轴上。")
case (0, _, 0): // 3
    print("在y轴上。")
case (0, 0, _): // 4
    print("在z轴上。")
default:        // 5
    print("空间里的某个位置")
}

这个switch语句利用了部分匹配(partial matching)。按顺序说一下每个case都做了什么:

  1. 恰好匹配值是(0, 0, 0)的情况。这是3D空间的原点。
  2. 匹配y=0, z=0以及任意的x值。这意味着坐标点在x轴上。
  3. 匹配x=0, z=0以及任意的y值。这意味着坐标点在y轴上。
  4. 匹配x=0, y=0以及任意的z值。这意味着坐标点在z轴上。
  5. 匹配剩下的坐标。

用下划线来表示你不在乎这个值。你早在第二篇文章就见过了,会并会在贯穿教程的多个地方看见它。因为这太好用了!

如果你不想忽略值,那你就能在switch语句里使用它,像这样:

let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (0, 0, 0):
    print("原点")
case (let x, 0, 0):
    print("在x轴上 x = \(x)")
case (0, let y, 0):
    print("在y轴上 y = \(y)")
case (0, 0, let z):
    print("在z轴上 z = \(z)")
case (let x, let y, let z):
    print("空间里的某个位置 x = \(x), y = \(y), z = \(z)")
}

这里坐标轴 case 使用 let 语法来把有关值取出。代码然后使用字符串插入来构建一个字符串,把它 print 出来。

注意为什么这个switch语句不需要一个default。这是因为最后的case本质上就是default—它匹配任何值,因为对元组的任一部分都没有限制。如果switch语句在cases里用光了所有可能的值,那就不需要什么default了。

最后,你也可以用与之前看到的同样的let-where语法来匹配更复杂的情况。例如:

let coordinates: (x: Int, y: Int, z: Int) = (3, 2, 5)
switch (coordinates) {
case (let x, let y, _) where y == x:
    print("在y = x线上。")
case (let x, let y, _) where y == x * x:
    print("在y = x^2线上。")
default:
    break
}

这里,你匹配了“y等于x”和“y等于x的平方”两条线。

这些就是switch语句的基础啦!

迷你练习

  1. 写一个switch语句,基于一个整数的年龄,然后print出这个年龄对应的年龄层。你可以自己做一个年龄层,或者用我的分类方法:0-2岁:幼儿,3-12岁:儿童,13-19岁:青少年,20-39岁:成年人,40-60:中年人;61+:老人。
  2. 写一个switch语句,基于包含了一个字符串和一个整数的元组。字符串是一个名字,整数是一个年龄。用和你在前一个练习同样的情况,用 let 语法来 print 出名字接着年龄层。例如,我自己就应该 print 出“张嘉夫是一个成年人。”

关键点

  • 用 if 语句做基于一个情况的简单判断。
  • 在 if 语句里用 else 和 else-if 来为做判断扩展,不止一个单独的情况。
  • 你可以在简单 if 语句的地方用三目操作符。
  • 变量和常量属于一个特定的scope(范围),越过了scope就不能再用他们了。一个scope可以继承父scope的变量和常量。
  • 用 switch 语句来基于一个变量或常量的值决定运行哪段代码。
  • switch 语句的强大来自于它使用模式匹配的能力,因为值可以用复杂规则来进行比较。

接下来去哪儿?

Apps很少全程时刻都运行在同样的方式;根据来自网络或用户输入的内容,你的代码需要做判断去哪条路。有了if,else和switch语句,你可以让代码基于一些情况来做决定。

和决定是否要做一些事相似,你也能决定做一些事多少次。在下一篇文章里,你会看到如何使用循环来多次重复步骤。

挑战

挑战A:你就是编译器

下面的代码哪里错了?

let firstName = "嘉夫"
if firstName == "嘉夫" {
    let lastName = "张"
} else if firstName == "阳" {
    let lastName = "刘"
}
let fullName = lastName + firstName

挑战B:结果预测

看看下面的switch语句:

switch (coordinates) {
case (let x, let y, let z) where x == y && y == z:
    print("x = y = z")
case (_, _, 0):
    print("在x/y平面上")
case (_, 0, _):
    print("在x/z片面上")
case (0, _, _):
    print("在y/z平面上")
default:
    print("没什么特别的")
}

在coordinates分别是下列每一个的时候,代码会 print 什么?

let coordinates = (1, 5, 0)
let coordinates = (2, 2, 2)
let coordinates = (3, 0, 1)
let coordinates = (3, 2, 5)
let coordinates = (0, 2, 4)

介绍

欢迎来到Swift世界!Swift是一门苹果在2014年夏天发布的编程语言。从那之后,Swift发布了一个主要的版本跳跃,成为了开始在苹果平台:iOS,OS X,watchOS和tvOS开发的最简单的方式。

谁适合这篇教程

这篇教程适合懂一点编程、并且希望学习Swift的人。也许你已经为网站写过一些JavaScript代码,或者用Python写过一些简短的程序。这篇教程就是为你准备的!你会学习到编程的基本概念,同时也会成为Swift语言小能手。

如果你是赤裸裸的编程新手,这篇教程也是为你准备的!教程里贯穿有简短的锻炼和挑战来给你一些编程练习,同时测试你的知识。

需要准备什么

要看这篇教程,你需要准备如下的东西:

  • 一台运行OS X El Captian(10.11)的Mac,带有最新发布的更新并且安装了安全补丁。这样你才能够安装需要的开发工具:最新版本的Xcode。
  • Xcode 7.3 或更新的版本。Xcode是用Swift写代码的主要开发工具。最小也需要Xcode 7.3版本,因为那个版本包含Swift 2.2。你可以免费从Mac App Store下载Xcode的最新版本,这里:http://apple.co/1FLn51R

如果你还没有安装Xcode最新版本,在继续看下面的教程前要确定安装。

如何使用这篇教程

每篇教程都会介绍触手可及的话题理论,伴随大量Swift代码来示范在学习的实际的应用程序。

教程里的所有代码都是平台中立的;这意味着不是为iOS、OS X或任何其它平台而特定。代码在playgrounds里运行,你在本篇中已经学习了。

在剩下的教程里,你可以把代码在自己的playground里输入进去。这样你就可以和代码“玩耍”(play around),做一些改变立即就能看见代码运行的结果。

剩下的教程里会贯穿实际小练习,都是简短的练习,关于触手可及的主题。每篇的末尾也有挑战,会有编程问题也会有长一点的代码练习来测试你的知识。做完就能掌握大部分的Swift基础知识。

教程更新

教程会随Swift语言的更新而更新,会发布在我的简书和知乎专栏上,搜索“张嘉夫”即可关注我。

目录

本教程从一些基础工作开始来让你起步:

  • 第1篇,编程本质 & Playground基础 - 这就是,到编程世界的入门介绍!你会从电脑和编程的预览开始,然后剩余时间给Swift playground打个招呼。
  • 第2篇,变量 & 常量 - 你会学习到变量和常量,这是用来存储数据的“地方”。你也会学习数据类型以及Swift如何追踪数据类型并在代码中进行传输。
  • 第3篇,数字类型 & 操作 - 你会从基础的数字类型比如整形和浮点型数字开始,当然也包括布尔类型。也会看到一些在实际操作,从比较到算数操作如加减。
  • 第4篇,字符串 - 用字符串来存储文字-从按钮里的文字到图片的标注到这篇教程全部的文字,存储这所有的一切!你会学习到string和character类型,以及基于这些类型的一些常见操作。

在脑海中有基础数据类型后,就该用那些数据做一些事情了:

  • 第5篇,做判断 - 代码不总是直接从头运行到尾。你会学习在代码里如何做判决并且设定情况来运行某段代码。
  • 第6篇,重复步骤 - 继续不要让代码直线运行的主题,你会学习到如何使用循环来重复某些步骤。
  • 第7篇,函数 - 函数是Swift中用来构建代码的基础建筑。你会学习到如何定义函数来分组代码到可复用单元中。
  • 第8篇,闭包(Closures) - 闭包和函数很接近。你会学习到如何使用它们来轻松传递代码块。

最后一篇会回到数据:

  • 第9节,可选值 - 这篇讲可选值,Swift中的一种特殊类型,表示既有可能是一个真实的值也有可能没有值。这篇的最后你会知道为什么要用可选值以及如何安全地使用它们。

这些基础会让你快速开始Swift之路,做好接触更高级编程主题的准备。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容