send和receive语句
send、receive操作是针对channel的
send : ch <- a
receive: a := <- ch
++
和--
语句
在go中++
和--
是一个赋值语句,而不是一个表达式因此不能像C/C++那样编写如下代码:
a = b++
同时在go中只有后置,没有前置写法。
a++
a--
if
语句
if
if是编程语言中最简单的条件分支判断语句,几乎所有语言都有,所以就不介绍功能,主要介绍下写法
if
语句中的条件表达式不需要加上括号
if a > 0 {
fmt.Println("a > 0")
} else {
fmt.Println("a <= 0")
}
if
的语句中可以在判断语句中声明变量,这个变量只在if语句作用域内部有效
if a := calc(); a < 0 {
fmt.Println("result:", a)
}
switch
语句
switch
语句中首先执行switch
后面的表达式,然后执行case
后面的表达式,并且是从上到下,从左到右执行,一旦有一个满足,则不再继续执行后面的操作。
switch
后面不跟表达式则默认为true
case
后面可以跟很多个表达式,其中一个满足则执行该case
下的语句
默认情况下case下的语句执行之后会跳出switch
,如果需要继续执行,使用fallthrough
关键字,即使是default
也可以fallthrough
和if
一样可以在switch
表达式中声明变量
switch
可以最多有一个default
,当没有case条件满足的情况下执行default
switch tag {
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}
switch {
case x < y : s1()
case x > y : s2()
case x = y : s3()
}
switch x := f(); { // default is true
case x < 0: return -x
default: return x
}
switch
出了支持上述普通的表达式判断以外,还支持类型switch,这种情况下不能使用fallthrough
type有可能是nil(当变量是一个nil interface的时候)
switch i := x.(type) {
case nil:
print("x is nil)
case int:
print("x is int")
case bool, string:
print("x is bool or string")
default:
print("x is a don't know type")
}
for
语句
for语句有三种形式:
- 无限循环
for {
dosomething()
}
- 类似C/C++的while形式
for a < b {
dosomething()
}
- 标准的for形式
for i := 0; i < 10; i++ {
dosomething()
}
对于数组、slice、string、map、channel可以是用for range的形式,具体情况如下:
- slice、array,返回一个index和index对应的element。
for index, value := range a {
}
- string,返回一个index和一个rune,index以byte计数,是rune在string的起始byte的index。一个rune占几个byte取决于该unicode的长度
b := "中文"
for index, unicode := range a {
fmt.Println(index, string(unicode))
}
//输出
//0 中
//3 文
- map,返回key和value
for key, value := range amap {
}
- channel,一个双向或者是接收channel,当没有数据的时候会阻塞,知道收到数据为止,channel是nil会永久阻塞,当channel关闭,循环退出
for k := range ch {}
go
语句
go语句创建一个goroutine并在该goroutine中执行函数,可以是一个匿名函数
go log(i)
go func(i int) {
log(i)
}(1)
select
语句
select
语句主要用于对channel的选择,可以是接收或者发送,当操作成功的时候的时候选择对应的case,如果有多个case成功,随机选择其中一个执行。
var a []int
var c, c1, c2, c3, c4 chan int
var i1, i2 int
select {
case i1 = <-c1:
print("received ", i1, " from c1\n")
case c2 <- i2:
print("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
print("received ", i3, " from c3\n")
} else {
print("c3 is closed\n")
}
case a[f()] = <-c4:
// same as:
// case t := <-c4
// a[f()] = t
default:
print("no communication\n")
}
for { // send random sequence of bits to c
select {
case c <- 0: // note: no statement, no fallthrough, no folding of cases
case c <- 1:
}
}
select {} // block forever
return
语句
return结束一个函数,并且可以返回一个或者多个返回值
func noResult() {
return
}
func twoResult() (int, bool) {
return 1, true
}
func towResultWithVariabl() (a int, b bool) {
a = 1
b = true
return //same as return a, b
}
break
break用于跳出最内层的for switch select语句,也可以通过使用label来跳出指定的label标记的for switch select
OUTER_LOOP:
for i := 0; i < 10; i++ {
for j := 0; j < 10; j++ {
switch a[i][j] {
case nil : break //跳出本次switch,same as no break.
case item: break OUTER_LOOP //直接跳出最外层循环
}
}
}
continue
continue
用于直接开始最内层循环的下一个迭代,也可以通过label来继续label标记的for loop。
RowLoop:
for y, row := range rows {
for x, data := range row {
if data == endOfRow {
continue RowLoop
}
row[x] = data + bias(x, y)
}
}
goto
和C/C++中的goto一样,跳转到指定的label处,goto不能跳过作用域中的变量声明,也不能跳转到不同的作用域中去
goto L
v := 3
L:
dosomething() //错误,跳过了v的声明
if n%2 == 1 {
goto L1
}
for n > 0 {
fn()
n--
L1
fn()
n--
}
//错误,从一个作用域跳转到另外一个作用域
defer
defer是一个函数的执行推迟到其调用defer的函数的return之前执行。
多个defer的执行顺序是和编写顺序逆序执行的
func dosomething() int {
}
func do() int {
lock(l)
defer unlock(l) //unlock will execute after dosomething
...
return dosomething()
}
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
这样将输出9到0
recover and panic
panic将直接从调用panic的当前函数中返回,并且如果panic没有被recover,那么程序将直接crash。
可以通过defer和recover来从panic错误中恢复。
func protect(g func()) {
defer func() {
log.Println("done") // Println executes normally even if there is a panic
//catch panic 并且从panic中恢复,以保证程序不会crash,而是可以继续执行。
if x := recover(); x != nil {
log.Printf("run time panic: %v", x)
}
}()
log.Println("start")
g()
}