『GoLang』控制结构
条件语句
if
是用于测试某个条件(布尔型或逻辑型)的语句,如果该条件成立,则会执行if
后由大括号括起来的代码块,否则就忽略该代码块继续执行后续的代码。
if condition {
// do something
}
如果存在第二个分支,则可以在上面代码的基础上添加 else
关键字以及另一代码块,这个代码块中的代码只有在条件不满足时才会执行。if
和 else
后的两个代码块是相互独立的分支,只可能执行其中一个。
if condition {
// do something
} else {
// do something
}
如果存在第三个分支,则可以使用下面这种三个独立分支的形式:
if condition1 {
// do something
} else if condition2 {
// do something else
} else {
// catch-all or default
}
else-if
分支的数量是没有限制的,但是为了代码的可读性,还是不要在if
后面加入太多的else-if
结构。如果你必须使用这种形式,则把尽可能先满足的条件放在前面。
关键字
if
和else
之后的左大括号{
必须和关键字在同一行,如果你使用了else-if
结构,则前段代码块的右大括号}
必须和else-if
关键字在同一行。这两条规则都是被编译器强制规定的。
【示例】
判断一个字符串是够为空:
if str == "" {...}
if len(str) == 0 {...}
判断运行 Go 程序的操作系统类型,这可以通过常量
runtime.GOOS
来判断if runtime.GOOS == "windows" {
...
} else { // Unix-like
...
}
这段代码一般被放在
init()
函数中执行。这儿还有一段示例来演示如何根据操作系统来决定输入结束的提示:var prompt = "Enter a digit, e.g. 3 "+ "or %s to quit." func init() {
if runtime.GOOS == "windows" {
prompt = fmt.Sprintf(prompt, "Ctrl+Z, Enter")
} else { //Unix-like
prompt = fmt.Sprintf(prompt, "Ctrl+D")
}
}
函数
Abs()
用于返回一个整型数字的绝对值:func Abs(x int) int {
if x < 0 {
return -x
}
return x
}
isGreater
用于比较两个整型数字的大小:func isGreater(x, y int) bool {
if x > y {
return true
}
return false
}
在条件语句中,还可以包含初始化语句:
if initialization; condition {
// do something
}
例如:
if val := 10; val > max {
// do something
}
但要注意的是,使用简短方式
:=
声明的变量的作用域只存在于if
结构中(在if
结构的大括号之间,如果使用if-else
结构则在else
代码块中变量也会存在)。如果变量在if
结构之前就已经存在,那么在if
结构中,该变量原来的值会被隐藏。最简单的解决方案就是不要在初始化语句中声明变量。
另外,
else-if
语句中也可以初始化变量,只是其作用域只在当前的else-if
语句到结尾的else
语句之间,在此之前的if
和else
语句是无法访问的。
switch 语句
相比较 C 和 Java 等其它语言而言,Go 语言中的 switch
结构使用上更加灵活。它接受任意形式的表达式:
switch var1 {
case val1:
...
case val2:
...
default:
...
}
变量
var1
可以是任何类型,而val1
和val2
则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式。前花括号{
必须和switch
关键字在同一行
可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:
case val1, val2, val3
每一个 case
分支都是唯一的,从上至下逐一测试,直到匹配为止。一旦成功地匹配到某个分支,在执行完相应代码后就会退出整个 switch
代码块,也就是说您不需要特别使用 break
语句来表示结束。因此,程序也不会自动地去执行下一个分支的代码。如果在执行完每个分支的代码后,还希望继续执行后续分支的代码,可以使用 fallthrough
关键字来达到目的。
switch i {
case 0: fallthrough
case 1:
f() // 当 i == 0 时函数也会被调用
}
fallthrough
关键字之后,在当前概念case
分支不能再出现语句了
在 case ...:
语句之后,不需要使用花括号将多行语句括起来,但可以在分支中进行任意形式的编码。当代码块只有一行时,可以直接放置在 case
语句之后。
同样可以使用 return
语句来提前结束代码块的执行。当在 switch
语句块中使用 return
语句,并且您的函数是有返回值的,还需要在 switch
之后添加相应的 return
语句以确保函数始终会返回。
可选的 default
分支可以出现在任何顺序,但最好将它放在最后。它的作用类似与 if-else
语句中的 else
,表示不符合任何已给出条件时,执行相关语句。
switch
语句的第二种形式是不提供任何被判断的值(实际上默认为判断是否为 true
),然后在每个 case
分支中进行测试不同的条件。当任一分支的测试结果为 true
时,该分支的代码会被执行。这看起来非常像链式的 if-else
语句,但是在测试条件非常多的情况下,提供了可读性更好的书写方式。
switch {
case i < 0:
f1()
case i == 0:
f2()
case i > 0:
f3()
}
前面的
switch
语句可以看做是值得判断,这里的switch
是布尔条件的判断
switch 语句的第三种形式是包含一个初始化语句:
switch initialization; expression {
case val1:
...
case val2:
...
default:
...
}
switch
语句还可以被用于type-switch
来判断某个 interface 变量中实际存储的变量类型,后面再说。
for 语句
基于计数器的迭代
如果想要重复执行某些语句,Go 语言中只有 for
结构可以使用。不要小看它,这个 for
结构比其它语言中的更为灵活。
最简单的基于计数器的迭代,基本形式为:
for 初始化语句; 条件语句; 修饰语句 {
...
}
这三部分组成的循环的头部,它们之间使用分号;
相隔,但并不需要括号 ()
将它们括起来。
还可以在循环中同时使用多个计数器:
for i, j := 0, N; i < j; i, j = i+1, j-1 {
...
}
同样的,左花括号
{
必须和for
语句在同一行,计数器的生命周期在遇到右花括号}
时便终止。一般习惯使用i
、j
、z
或ix
等较短的名称命名计数器。
特别注意,永远不要在循环体内修改计数器,这在任何语言中都是非常差的实践!
可以将两个 for
循环嵌套起来:
for i:=0; i<5; i++ {
for j:=0; j<10; j++ {
println(j)
}
}
基于条件判断的迭代
for
结构的第二种形式是没有头部的条件判断迭代(类似其它语言中的 while
循环),基本形式为:
for 条件语句 {
...
}
也可以认为这是没有初始化语句和修饰语句的 for
结构,因此 ;;
便是多余的了。
package main
import "fmt"
func main() {
var i int = 5
for i >= 0 {
i = i - 1
fmt.Printf("The variable i is now: %d\n", i)
}
}
/*
* 输出:
* The variable i is now: 4
* The variable i is now: 3
* The variable i is now: 2
* The variable i is now: 1
* The variable i is now: 0
* The variable i is now: -1
*/
无限循环
条件语句是可以被省略的,如 i:=0; ; i++
或 for { }
或 for ;; { }
(;;
会在使用 gofmt 时被移除):这些循环的本质就是无限循环。最后一个形式也可以被改写为 for true { }
,但一般情况下都会直接写 for { }
。
如果 for
循环的头部没有条件语句,那么就会认为条件永远为 true
,因此循环体内必须有相关的条件判断以确保会在某个时刻退出循环。
无限循环的经典应用是服务器,用于不断等待和接受新的请求。
for t, err = p.Token(); err == nil; t, err = p.Token() {
...
}
for-range 结构
for-range
结构是 Go 语言特有的一种迭代结构,它在许多情况下都非常有用。它可以迭代任何一个集合,包括数组(array
)和字典(map
),同时可以获得每次迭代所对应的索引和值。一般形式为:
for ix, val := range coll { }
要注意的是,val
始终为集合中对应索引的值的副本,因此它一般只具有只读性质,对它所做的任何修改都不会影响到集合中原有的值(注:如果 val
为指针,则会产生指针的副本,依旧可以修改集合中的原值)。一个字符串是 Unicode 编码的字符(或称之为 rune
)集合,因此您也可以用它迭代字符串:
for pos, char := range str {
...
}
每个
rune
字符和索引在for-range
循环中是一一对应的。它能够自动根据 UTF-8 规则识别 Unicode 编码的字符。
还有其他一些用法,等说道相应的内容再举例
break和continue
- break:
一般而言,直接结束最近的一层循环。但在switch
或select
语句中,break
语句的作用结果是跳过整个代码块,执行后续的代码。 - continue:
结束本次迭代,直接开始下一次迭代,但不是无条件执行下一次循环,执行之前依旧需要满足循环的判断条件。 关键字continue
只能被用于for
循环中。
标签与goto
for
、switch
或 select
语句都可以配合标签(label
)形式的标识符使用,即某一行第一个以冒号(:
)结尾的单词(gofmt 会将后续代码自动移至下一行)
package main
import "fmt"
func main() {
LABEL1:
for i := 0; i <= 5; i++ {
for j := 0; j <= 5; j++ {
if j == 4 {
continue LABEL1
}
fmt.Printf("i is: %d, and j is: %d\n", i, j)
}
}
}
本例中,
continue
语句指向LABEL1
,当执行到该语句的时候,就会跳转到LABEL1
标签的位置。
【注意】
continue
可以用break
和goto
关键字替代,但是作用可能不同。
continue
和break
是指将自身功能作用到标签同一级别的循环体(例如多层循环,你想break
直接结束整体的循环,就需要标签),goto
是直接到那一行执行,容易造成死循环。
『GoLang』控制结构的更多相关文章
- 『Golang』Martini框架入门
本文介绍golang中的优秀web开发框架martini! 序 Martini框架是使用Go语言作为开发语言的一个强力的快速构建模块化web应用与服务的开发框架.Martini是一个专门用来处理Web ...
- 『Golang』MongoDB在Golang中的使用(mgo包)
有关在Golang中使用mho进行MongoDB操作的最简单的例子.
- 『Golang』在Golang中使用json
由于要开发一个小型的web应用,而web应用大部分都会使用json作为数据传输的格式,所以有了这篇文章. 包引用 import ( "encoding/json" "gi ...
- 『Golang』—— 标准库之 os
Golang 的 os 库基本承袭 Unix 下 C 语言的用法 path 库: func Base(path string) string //取文件名,不含目录部分 func Dir(path s ...
- 『GoLang』fmt包的使用
目录 1. fmt 包初识 2. 格式化 verb 应用 2.1 通用 2.2 布尔值 2.3 整数 2.4 浮点数与复数 2.5 字符串和 []byte 2.6 指针 2.7 其他 flag 2.8 ...
- 『GoLang』string及其相关操作
目录 1. 字符串简介 2. 字符串的拼接 3. 有关 string 的常用处理 3.1 strings 包 3.1.1 判断两个 utf-8 编码字符串是否相同 3.1.2 判断字符串 str 是否 ...
- 『Golang』跨平台TUI(基于文字的用户界面)库Terbox-Go文档翻译
原文 package termbox import "github.com/nsf/termbox-go" termbox-go 是一个用于创建跨平台TUI(基于文本的用户界面)的 ...
- 『Golang』Go简介以及环境搭建
简介 go语言是由Google进行维护的一个编程语言,发布自2009年.其以良好的编程风格.优秀的并发机制被广大的技术人员所接受. 使用go语言开发的优秀的产品: Docker gocode lime ...
- 『Golang』—— 标准库之 time
... package main import ( "fmt" "time" ) func main() { time.AfterFunc(time.Milli ...
随机推荐
- 题解 P3158 [CQOI2011]放棋子
题解 本题是一个 \(DP\) 加 容斥,容斥的式子很好推,重点是如何想到和如何推出 \(DP\) 部分的式子. 因为不同种颜色的棋子不能放在同一行或同一列,所以不同种的棋子是相对独立的. 据此,我们 ...
- HTML <form> 标签的 method 属性
定义和用法 method 属性规定如何发送表单数据(表单数据发送到 action 属性所规定的页面). 表单数据可以作为 URL 变量(method="get")或者 HTTP p ...
- C#多线程详解(一) Thread.Join()的详解
bicabo C#多线程详解(一) Thread.Join()的详解 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程 ...
- 数据库中sql分类
-- sql语句分类:-- 1)数据定义语句(DDL):-- create/alter/drop-- 2)数据操作语句(DML):-- insert ...
- 初识apache DBCP连接池
连接案例: 首先:我们使用的是mysql数据库,所以要有一个mysql和java的JDBCjar包: 然后是DBCP中的两个jar包,DBCP使用的话,需要两个包: dbcp.jar和pool.jar ...
- linux高级监控atop的使用
一.centos安装 sudo yum -y install epel-release.noarch sudo yum -y install atop sudo systemctl enable at ...
- go实现堆排序
package main import "fmt" func main(){ arr:=[]int{4,8,2,1,6,9,3,5,7,8,1,4} dui(arr) fmt.Pr ...
- IDEA常用设置及推荐插件
IDEA常用设置及推荐插件 本文主要记录IDEA的一些常用设置,IDEA与Eclipse的常用快捷键对比及推荐一些好用的插件. 基本设置 设置界面风格及修改外部UI尺寸大小 打开IDEA时设置不重新打 ...
- Ubuntu 16.04 NVidia显卡 输入密码后 重复出现登录界面
问题根源:显卡驱动 解决办法: CTRL+ALT+F1 # 切换到命令行 sudo service lightdm stop # 关闭桌面显示管理器 sudo apt-get remove --pu ...
- GO的GC辣鸡回收(一)
用户程序通过内存分配器(Allocator)在堆上申请内存,而垃圾收集器(Collector)负责回收堆上的内存空间,内存分配器和垃圾收集器共同管理程序中的堆内存空间. 基本概念 垃圾分类 语义垃圾: ...