Golang通脉之流程控制详情

目录
  • 1、if else(分支结构)
    • 1.1 if条件判断基本写法
    • 1.2 if条件判断特殊写法
  • 2、for(循环结构)
    • 2.1 无限循环
  • 3、for range(键值循环)
  • 4、switch case
  • 5、goto(跳转到指定标签)
  • 6、break(跳出循环)
  • 7、continue(继续下次循环)

前言:

流程控制是每种编程语言控制逻辑走向和执行次序的重要部分,流程控制可以说是一门语言的“经脉”。

Go语言中最常用的流程控制有iffor,而switchgoto主要是为了简化代码、降低重复代码而生的结构,属于扩展类的流程控制。

1、if else(分支结构)

1.1 if条件判断基本写法

Go语言中if条件判断的格式如下:

if 表达式1 {
    分支1
} else if 表达式2 {
    分支2
} else{
    分支3
}

当表达式1的结果为true时,执行分支1,否则判断表达式2,如果满足则执行分支2,都不满足时,则执行分支3。 if判断中的else ifelse都是可选的,可以根据实际需要进行选择。

关于 if 条件语句的使用有一些规则:

  • if 后面的条件表达式不需要使用 (),这和有些编程语言不一样,也更体现 Go 语言的简洁;
  • 每个条件分支(if 或者 else)中的大括号是必须的,哪怕大括号里只有一行代码(如示例);
  • if 紧跟的大括号 { 不能独占一行,else 前的大括号 } 也不能独占一行,否则会编译不通过;
  • if……else 条件语句中还可以增加多个 else if,增加更多的条件分支。

1.2 if条件判断特殊写法

if条件判断还有一种特殊的写法,可以在 if 表达式之前添加一个执行语句,再根据变量值进行判断:

func main() {
    if i:=6; i >10 {
        fmt.Println("i>10")
    } else if  i>5 && i<=10 {
        fmt.Println("5<i<=10")
    } else {
        fmt.Println("i<=5")
    }
}

2、for(循环结构)

Go 语言中的所有循环类型均可以使用for关键字来完成。

for循环的基本格式如下:

for 初始语句;条件表达式;更新语句{
    循环体语句
}

条件表达式返回true时循环体不停地进行循环,直到条件表达式返回false时自动退出循环。

func forDemo() {
 for i := 0; i < 10; i++ {
  fmt.Println(i)
 }
}

for循环的初始语句可以被忽略,但是初始语句后的分号必须要写,例如:

func forDemo2() {
 i := 0
 for ; i < 10; i++ {
  fmt.Println(i)
 }
}

for循环的初始语句和结束语句都可以省略,例如:

func forDemo3() {
 i := 0
 for i < 10 {
  fmt.Println(i)
  i++
 }
}

这种写法类似于其他编程语言中的while,在while后添加一个条件表达式,满足条件表达式时持续循环,否则结束循环。

2.1 无限循环

for {
    循环体语句
}

for循环可以通过breakgotoreturnpanic语句强制退出循环。

Go 语言中,同样支持使用 continuebreak 控制 for 循环:

continue 可以跳出本次循环,继续执行下一个循环。

break 可以跳出整个 for 循环,哪怕 for 循环没有执行完,也会强制终止。

3、for range(键值循环)

Go语言中可以使用for range遍历数组、切片、字符串、map 及通道(channel)。

通过for range遍历的返回值有以下规律:

  • 数组、切片、字符串返回索引和值。
  • map返回键和值。
  • 通道(channel)只返回通道内的值。

注意:

与 for 不同的是,range 对每个迭代值都创建了一个拷贝。因此如果每次迭代的值内存占用很小的情况下,for 和 range 的性能几乎没有差异,但是如果每个迭代值内存占用很大,这种情况下差距就非常明显了。

简单的例子证明 range 迭代时,返回的是拷贝。

persons := []struct{ no int }{{no: 1}, {no: 2}, {no: 3}}
for _, s := range persons {
    s.no += 10
}
for i := 0; i < len(persons); i++ {
    persons[i].no += 100
}
fmt.Println(persons) // [{101} {102} {103}]
  • persons 是一个长度为 3 的切片,每个元素是一个结构体。
  • 使用 range 迭代时,试图将每个结构体的 no 字段增加 10,但修改无效,因为 range 返回的是拷贝。
  • 使用 for 迭代时,将每个结构体的 no 字段增加 100,修改有效

range 在迭代过程中返回的是迭代值的拷贝,如果每次迭代的元素的内存占用很低,那么 for 和 range 的性能几乎是一样,例如 []int。但是如果迭代的元素内存占用较高,例如一个包含很多属性的 struct 结构体,那么 for 的性能将显著地高于range,有时候甚至会有上千倍的性能差异。对于这种场景,建议使用 for,如果使用 range,建议只迭代下标,通过下标访问迭代值,这种使用方式和 for 就没有区别了。如果想使用 range 同时迭代下标和值,则需要将切片/数组的元素改为指针,才能不影响性能。

4、switch case

使用switch语句可方便地对大量的值进行条件判断。

func switchDemo1() {
 finger := 3
 switch finger {
 case 1:
  fmt.Println("大拇指")
 case 2:
  fmt.Println("食指")
 case 3:
  fmt.Println("中指")
 case 4:
  fmt.Println("无名指")
 case 5:
  fmt.Println("小拇指")
 default:
  fmt.Println("无效的输入!")
 }
}

Go语言规定每个switch只能有一个default分支。

一个分支可以有多个值,多个case值中间使用英文逗号分隔。

func testSwitch3() {
 switch n := 7; n {
 case 1, 3, 5, 7, 9:
  fmt.Println("奇数")
 case 2, 4, 6, 8:
  fmt.Println("偶数")
 default:
  fmt.Println(n)
 }
}

分支还可以使用表达式,这时候switch语句后面不需要再跟判断变量:

func switchDemo4() {
 age := 30
 switch {
 case age < 25:
  fmt.Println("好好学习吧")
 case age > 25 && age < 35:
  fmt.Println("好好工作吧")
 case age > 60:
  fmt.Println("好好享受吧")
 default:
  fmt.Println("活着真好")
 }
}

在 Go 语言中,switch case 从上到下逐一进行判断,一旦满足条件,立即执行对应的分支并返回,其余分支不再做判断。也就是说 Go 语言的 switch 在默认情况下,case 最后自带 break。这和其他编程语言不一样,比如 C 语言在 case 分支里必须要有明确的 break 才能退出一个 case。Go 语言的这种设计就是为了防止忘记写 break 时,下一个 case 被执行。

fallthrough语法可以执行满足条件的case的下一个case,是为了兼容C语言中的case设计的。

func switchDemo5() {
 s := "a"
 switch {
 case s == "a":
  fmt.Println("a")
  fallthrough
 case s == "b":
  fmt.Println("b")
 case s == "c":
  fmt.Println("c")
 default:
  fmt.Println("...")
 }
}

输出:

a
b

5、goto(跳转到指定标签)

goto语句通过标签进行代码间的无条件跳转。goto语句可以在快速跳出循环、避免重复退出上有一定的帮助。Go语言中使用goto语句能简化一些代码的实现过程。

例如双层嵌套的for循环要退出时:

func gotoDemo1() {
 var breakFlag bool
 for i := 0; i < 10; i++ {
  for j := 0; j < 10; j++ {
   if j == 2 {
    // 设置退出标签
    breakFlag = true
    break
   }
   fmt.Printf("%v-%v\n", i, j)
  }
  // 外层for循环判断
  if breakFlag {
   break
  }
 }
}

使用goto语句能简化代码:

func gotoDemo2() {
 for i := 0; i < 10; i++ {
  for j := 0; j < 10; j++ {
   if j == 2 {
    // 设置退出标签
    goto breakTag
   }
   fmt.Printf("%v-%v\n", i, j)
  }
 }
 return
 // 标签
breakTag:
 fmt.Println("结束for循环")
}

6、break(跳出循环)

break语句可以结束forswitchselect的代码块。

break语句还可以在语句后面添加标签,表示退出某个标签对应的代码块,标签要求必须定义在对应的forswitchselect的代码块上。 举个例子:

func breakDemo1() {
BREAKDEMO1:
 for i := 0; i < 10; i++ {
  for j := 0; j < 10; j++ {
   if j == 2 {
    break BREAKDEMO1
   }
   fmt.Printf("%v-%v\n", i, j)
  }
 }
 fmt.Println("...")
}

7、continue(继续下次循环)

continue语句可以结束当前循环,开始下一次的循环迭代过程,仅限在for循环内使用。

continue语句后添加标签时,表示开始标签对应的循环。例如:

func continueDemo() {
forloop1:
 for i := 0; i < 5; i++ {
  // forloop2:
  for j := 0; j < 5; j++ {
   if i == 2 && j == 2 {
    continue forloop1
   }
   fmt.Printf("%v-%v\n", i, j)
  }
 }
}

到此这篇关于Golang通脉之流程控制详情的文章就介绍到这了,更多相关Golang通脉之流程控制内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Golang 语言控制并发 Goroutine的方法

    goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理.Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU. 01介绍 Golang 语言的优势之一是天生支持并发,我们在 Golang 语言开发中,通常使用的并发控制方式主要有 Channel,WaitGroup 和 Context,本文我们主要介绍一下 Golang 语言中并发控制的这三种方式怎么使用?关于它们各自的详细介绍在之前的文章已经介绍过,感兴趣的读者朋友们可以按需翻阅. 02

  • Golang 探索对Goroutine的控制方法(详解)

    前言 在golang中,只需要在函数调用前加上关键字go即可创建一个并发任务单元,而这个新建的任务会被放入队列中,等待调度器安排.相比系统的MB级别线程栈,goroutine的自定义栈只有2KB,这使得我们能够轻易创建上万个并发任务,如此对性能提升不少.但随之而来的有以下几个问题: 如何等待所有goroutine的退出 如何限制创建goroutine的数量(信号量实现) 怎么让goroutine主动退出 探索--如何从外部杀死goroutine 本文记录了笔者就以上几个问题进行探究的过程,文中给

  • Golang学习笔记(三):控制流

    控制结构分为: 条件+选择+循环 IF 1.说明 复制代码 代码如下: 条件表达式没有括号 支持一个初始化表达式(可以是多变量初始化语句) 初始化语句中定义的都是只能在block级别中使用的局部变量,不能在block之外使用 左大括号必须和条件语句在同一行(必须与if/else在同一行) go没有三元运算符 if判断语句条件不需要括号 在判断语句里卖弄允许声明一个变量,其作用域只在逻辑块内,其他地方不起作用 花括号一定存在,且必须与if/else在同一行 2.语法 复制代码 代码如下: //基本

  • golang通过context控制并发的应用场景实现

    golang 里出现多 goroutine 的场景很常见, 最常用的两种方式就是 WaitGroup 和 Context, 今天我们了解一下 Context 的应用场景 使用场景 场景一: 多goroutine执行超时通知 并发执行的业务中最常见的就是有协程执行超时, 如果不做超时处理就会出现一个僵尸进程, 这累计的多了就会有一阵手忙脚乱了, 所以我们要在源头上就避免它们 看下面这个示例: package main import ( "context" "fmt"

  • GoLang之使用Context控制请求超时的实现

    起因   之前接触了一个需求:提供一个接口,这个接口有一个超时时间,如果超时了返回超时异常:这个接口中调用其他的接口,如果调用超时了,所有请求全部结束.   在这个接口中,我使用了go协程去调用其他接口,所以不仅涉及到请求的超时控制,而且还涉及到父协程对子协程的控制问题.在翻阅了一些资料之后,了解到了Context的基本知识. Context   Context是golang.org.pkg下的一个包,类型是接口类型.主要功能有 父协程控制所有的子协程   Context可以通过context.

  • Golang 实现分片读取http超大文件流和并发控制

    分片读取http超大文件流 Golang中的HTTP发送get请求,在获取内容有两种情况. Golang发送http get请求方式 resp, err := http.Get(sendUrl) if err != nil { fmt.Println("出错", err) return } 第一种方式是直接全部读取出来,这种方式在小数据量的时候很方便. body变量直接全部接收resp响应内容 body, err2 := ioutil.ReadAll(resp.Body) 第二种方式,

  • 详解Golang 中的并发限制与超时控制

    前言 上回在 用 Go 写一个轻量级的 ssh 批量操作工具里提及过,我们做 Golang 并发的时候要对并发进行限制,对 goroutine 的执行要有超时控制.那会没有细说,这里展开讨论一下. 以下示例代码全部可以直接在 The Go Playground上运行测试: 并发 我们先来跑一个简单的并发看看 package main import ( "fmt" "time" ) func run(task_id, sleeptime int, ch chan st

  • golang实现并发数控制的方法

    golang并发 谈到golang这门语言,很自然的想起了他的的并发goroutine.这也是这门语言引以为豪的功能点.并发处理,在某种程度上,可以提高我们对机器的使用率,提升系统业务处理能力.但是并不是并发量越大越好,太大了,硬件环境就会吃不消,反而会影响到系统整体性能,甚至奔溃.所以,在使用golang提供便捷的goroutine时,既要能够实现开启并发,也要学会如果控制并发量. 开启golang并发 golang开启并发处理非常简单,只需要在调用函数时,在函数前边添加上go关键字即可.如下

  • Golang通脉之流程控制详情

    目录 1.if else(分支结构) 1.1 if条件判断基本写法 1.2 if条件判断特殊写法 2.for(循环结构) 2.1 无限循环 3.for range(键值循环) 4.switch case 5.goto(跳转到指定标签) 6.break(跳出循环) 7.continue(继续下次循环) 前言: 流程控制是每种编程语言控制逻辑走向和执行次序的重要部分,流程控制可以说是一门语言的"经脉". Go语言中最常用的流程控制有if和for,而switch和goto主要是为了简化代码.

  • Go语言流程控制详情

    目录 1.流程控制 2.if 语句 3.goto 4.for语句 5.switch 1.流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑. 流程控制包含分三大类:条件判断,循环控制和无条件跳转. 2.if 语句 if 也许是各种编程语言中最常见的了,它的语法概括起来就是: 如果满足条件就做某事,否则做另一件事. Go 里面 if 条件判断语句中不需要括号,如下代码所示: if x > 10 {     fmt.Println("x i

  • Python执行流程控制 详情

    目录 一 引子 二 分支结构 2.1 什么是分支结构 2.2 为什么要用分支结构 2.3 如何使用分支结构 2.3.1 if语法 2.3.2 if应用案例 三 循环结构 3.1 什么是循环结构 3.2 为什么要用循环结构 3.3 如何使用循环结构 3.3.1 while循环语法 3.3.2 while循环应用案例 3.3.3 for循环语法 3.3.4 for循环应用案例 一 引子 流程控制即控制流程,具体指控制程序的执行流程,而程序的执行流程分为三种结构:顺序结构(之前我们写的代码都是顺序结构

  • Golang通脉方法详情

    目录 方法和接收者 指针类型的接收者 值类型的接收者 方法和函数 任意类型添加方法 方法继承 方法重写 结构体和方法补充 方法和接收者 Go语言中的方法(Method)是一种作用于特定类型变量的函数.这种特定类型变量叫做接收者(Receiver).接收者的概念就类似于其他语言中的this或者 self. Go 语言中同时有函数和方法.一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针.所有给定类型的方法属于该类型的方法集 方法只是一个函数,它带有一个特殊

  • Golang通脉之map详情

    目录 1.定义 2.基本使用 3.判断键是否存在 4.map的遍历 5.delete()函数删除map元素 6.指定顺序遍历map 7.map类型的切片 8.value为切片类型的map 9.map是引用类型 Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现. map 是一种无序的键值对的集合.map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值 map 是一种集合,所以可以像迭代数组和切片那样迭代它.不过,map 是无序的,无法决定它的返回

  • Golang通脉之数据类型详情

    目录 1.标识符与关键字 1.1 标识符 1.2 关键字 2.变量 2.1 什么是变量 2.2 变量类型 2.3 变量声明 3.常量 3.1 iota 4.基本数据类型 4.1 整型 4.2 浮点型 4.3 复数 4.4 布尔值 4.5 字符串 4.6 byte和rune类型 4.7 类型转换 5.运算符 5.1 算数运算符 5.2 关系运算符 5.3 逻辑运算符 5.4 位运算符 5.5 赋值运算符 5.6 运算符优先级 1.标识符与关键字 在了解数据类型之前,先了解一下go的标识符和关键字

  • Golang通脉之方法详情

    目录 方法和接收者 指针类型的接收者 值类型的接收者 方法和函数 任意类型添加方法 方法继承 方法重写 结构体和方法补充 方法和接收者 Go语言中的方法(Method)是一种作用于特定类型变量的函数.这种特定类型变量叫做接收者(Receiver).接收者的概念就类似于其他语言中的this或者 self. Go 语言中同时有函数和方法.一个方法就是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针.所有给定类型的方法属于该类型的方法集 方法只是一个函数,它带有一个特殊

  • Golang切片Slice功能操作详情

    目录 一.概述 二.切片 2.1 切片的定义 2.2 切片的长度和容量 2.3 切片表达式 简单切片表达式 完整切片表达式 2.4 使用make()函数构造切片 2.5 for range循环迭代切片 2.6 切片的本质 2.7 判断切片是否为空 三.切片功能操作 3.1 切片不能直接比较 3.2 切片的赋值拷贝 3.3 使用copy()函数复制切片 3.4 append()方法为切片添加元素 3.5 从切片中删除元素 从开头位置删除 从中间位置删除 从尾部删除 3.6 切片的扩容策略 一.概述

  • Python 流程控制实例代码

    首先,介绍if-else条件语句.if语句是用来根据表达式的真假来有选择的执行特定的程序块,控制程序的流程.用法同java等语言.对于else if,有一个elif的简写方式. 例如: 复制代码 代码如下: if x > 3: print("greater") elif x == 3: print("eq") else: print("small") 接下来介绍while语句.while语句的作用是在条件表达式为真时,重复执行特定的程序块.

  • Erlang中的函数与流程控制介绍

    一:函数 1:在Erlang中,[名字相同但参数数目不同]的两个函数是完全不同的函数. 2:其他模块内的函数用完全限定名称 被调用: 复制代码 代码如下: -module(sort1). -export([reverse_sort/1, sort/1]). reverse_sort(L) ->         lists1:reverse(sort(L)). sort(L) ->         lists:sort(L). 3:子句间以分号[;]分隔,在最后的结尾处以[.]结尾. 4:每个函

随机推荐