Go-流程控制

栏目: Go · 发布时间: 5年前

内容简介:if标识符的重声明和标识符的遮蔽上述代码被执行完毕之后,第二次声明的

if

if 100 > number {
    number += 3
} else if 100 < number {
    number -= 2
} else {
    fmt.Println("OK!")
}
//变量赋值
if number := 4; 100 > number {
    number += 3
}
// 标识符的重声明和标识符的遮蔽
var number int
if number := 4; 100 > number {
    number += 3
}

标识符的重声明和标识符的遮蔽

上述代码被执行完毕之后,第二次声明的 number 变量的值会是 7 ,而第一次声明的 number 变量的值仍会是 0

switch

names := []string{"Golang", "Java", "Rust", "C"}
switch name := names[0]; name {
case "Golang":
    fmt.Println("A programming language from Google.")
case "Rust":
    fmt.Println("A programming language from Mozilla.")
default:
    fmt.Println("Unknown!")
}
v := 11
switch i := interface{}(v).(type) {
case int, int8, int16, int32, int64:
    fmt.Printf("A signed integer: %d. The type is %T. \n", i, i)
case uint, uint8, uint16, uint32, uint64:
    fmt.Printf("A unsigned integer: %d. The type is %T. \n", i, i)
default:
    fmt.Println("Unknown!")
}

for语句

for i := 0; i < 10; i++ {
    fmt.Print(i, " ")
}
for i, v := range "Go语言" {
    fmt.Printf("%d: %c\n", i, v)
} 
/* print
0: G
1: o
2: 语
5: 言   
*/
// 注意,一个中文字符在经过UTF-8编码之后会表现为三个字节。
/*
range表达式的结果值的类型应该是能够被迭代的,包括:
字符串类型、
数组类型、
数组的指针类型、
切片类型、
字典类型
通道类型
for语句每次会迭代出两个值。
第一个值代表第二个值在字符串中的索引,
第二个值则代表该字符串中的某一个字符。
*/

最后,我们来说一下 break 语句和 continue 语句。它们都可以被放置在 for 语句的代码块中。break被执行时会使其所属的 for 语句的执行立即结束,continue被执行时会使当次迭代被中止(当次迭代的后续语句会被忽略)而直接进入到下一次迭代。

select语句

select 语句属于条件分支流程控制方法,不过它只能用于通道。它可以包含若干条 case 语句,并根据条件选择其中的一个执行。进一步说, select 语句中的 case 关键字只能后跟用于通道的发送操作的表达式以及接收操作的表达式或语句。

ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
// 省略若干条语句
select {
case e1 := <-ch1:
    fmt.Printf("1th case is selected. e1=%v.\n", e1)
case e2 := <-ch2:
    fmt.Printf("2th case is selected. e2=%v.\n", e2)
default:
    fmt.Println("No data!")
}

如果该 select 语句被执行时通道 ch1ch2 中都没有任何数据,那么肯定只有 default case 会被执行。但是,只要有一个通道在当时有数据就不会轮到 default case 执行了。显然,对于包含通道接收操作的 case 来讲,其执行条件就是通道中存在数据(或者说通道未空)。如果在当时有数据的通道多于一个,那么 Go 语言会通过一种伪随机的算法来决定哪一个 case 将被执行。

我们一直在说 case 执行条件的满足与否取决于其操作的通道在当时的状态。这里特别强调一点,即:未被初始化的通道会使操作它的 case 永远满足不了执行条件。对于针对它的发送操作和接收操作来说都是如此。

ch4 := make(chan int, 1)
for i := 0; i < 4; i++ {
    select {
    case e, ok := <-ch4:
        if !ok {
            fmt.Println("End.")
            return
        }
        fmt.Println(e)
        close(ch4)
    default:
        fmt.Println("No Data!")
        ch4 <- 1
    }
}

defer语句 [dɪˈfɚ] 推迟

defer 语句仅能被放置在函数或方法中。它由关键字 defer 和一个调用表达式组成。注意,这里的调用表达式所表示的既不能是对Go语言内建函数的调用也不能是对Go语言标准库代码包 unsafe 中的那些函数的调用。

func readFile(path string) ([]byte, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()
    return ioutil.ReadAll(file)
}

注意,当这条 defer 语句被执行的时候,其中的这条表达式语句并不会被立即执行。它的确切的执行时机是在其所属的函数(这里是 readFile )的执行即将结束的那个时刻。也就是说,在 readFile 函数真正结束执行的前一刻, file.Close() 才会被执行。

注意,当一个函数中存在多个 defer 语句时,它们携带的表达式语句的执行顺序一定是它们的出现顺序的倒序。

最后,对于 defer 语句,我还有两个特别提示:

  1. defer 携带的表达式语句代表的是对某个函数或方法的调用。这个调用可能会有参数传入,比如: fmt.Print(i + 1) 。如果代表传入参数的是一个表达式,那么在 defer 语句被执行的时候该表达式就会被求值了。注意,这与被携带的表达式语句的执行时机是不同的。
  2. 如果defer携带的表达式语句代表的是对匿名函数的调用,那么我们就一定要非常警惕。正确的用法是:把要使用的外部变量作为参数传入到匿名函数中。
func deferIt4() {
    for i := 1; i < 5; i++ {
        defer func(n int) {
            fmt.Print(n)
        }(i)
    }
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Little MLer

The Little MLer

Matthias Felleisen、Daniel P. Friedman、Duane Bibby、Robin Milner / The MIT Press / 1998-2-19 / USD 34.00

The book, written in the style of The Little Schemer, introduces instructors, students, and practicioners to type-directed functional programming. It covers basic types, quickly moves into datatypes, ......一起来看看 《The Little MLer》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码