巨细靡遗流程控制,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang流程结构详解EP09

简介: 流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序。众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang程序的流程控制结构一共有三种:顺序结构,选择结构,循环结构。顺序结构:从上向下,逐行执行;选择结构:条件满足,某些代码才会执行,0-1次;循环结构:条件满足,某些代码会被反复的执行多次,0-N次

流程结构就是指程序逻辑到底怎么执行,进而言之,程序执行逻辑的顺序。众所周知,程序整体都是自上由下执行的,但有的时候,又不仅仅是从上往下执行那么简单,大体上,Go lang程序的流程控制结构一共有三种:顺序结构,选择结构,循环结构。顺序结构:从上向下,逐行执行;选择结构:条件满足,某些代码才会执行,0-1次;循环结构:条件满足,某些代码会被反复的执行多次,0-N次

选择结构之条件判断if/else

市面上的语言都有if/else逻辑,逻辑非常简单,只要满足条件,就会执行条件代码块的逻辑:

if 布尔表达式 {  
   /* 在布尔表达式为 true 时执行 */  
}  
  
if 布尔表达式 {  
   /* 在布尔表达式为 true 时执行 */  
} else {  
  /* 在布尔表达式为 false 时执行 */  
}  
  
if 布尔表达式1 {  
   /* 在布尔表达式1为 true 时执行 */  
} else if 布尔表达式2{  
   /* 在布尔表达式1为 false ,布尔表达式2为true时执行 */  
} else{  
   /* 在上面两个布尔表达式都为false时,执行*/  
}

具体逻辑:

package main  
  
import "fmt"  
  
func main() {  
  
    var a int = 1  
  
    /* 使用 if 语句判断布尔表达式 */  
    if a < 20 {  
        /* 如果条件为 true 则执行以下语句 */  
        fmt.Printf("a 小于 20\n")  
    }  
    fmt.Printf("a 的值为 : %d\n", a)  
}

程序返回:

a 小于 20  
a 的值为 : 1

需要注意的是,条件变量类型要一致才能比较。

除此之外,if还可以在判断之前执行逻辑:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    if num := 10; num%2 == 0 { //checks if number is even  
        fmt.Println(num, "is even")  
    } else {  
        fmt.Println(num, "is odd")  
    }  
} 

程序返回:

10 is even

也就是说,当判断变量num对2取余是否等于0之前,我们可以先给num进行赋值操作。

同时if/else也支持多分支判断:



package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    score := 88  
    if score >= 90 {  
        fmt.Println("成绩等级为A")  
    } else if score >= 80 {  
        fmt.Println("成绩等级为B")  
    } else if score >= 70 {  
        fmt.Println("成绩等级为C")  
    } else if score >= 60 {  
        fmt.Println("成绩等级为D")  
    } else {  
        fmt.Println("成绩等级为E 成绩不及格")  
    }  
}

程序返回:

成绩等级为B

这里程序根据变量的值而选择执行不同的分支代码,但需要注意的是,Go lang对于 { 和 } 的位置有严格的要求,它要求 else if (或 else ) 和两边的花括号,必须在同一行。即使在 { 和 } 之间只有一条语句,这两个花括号也是不能省略的。

选择结构之选择判断switch

switch关键字是一个条件语句,它计算表达式并将其与可能匹配的列表进行比较,并根据匹配执行代码块。它可以被理解为用一种普适的方式来写多个if else判断子句。

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。 switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加break。

说白了就是,每一个case都默认自动break,执行完了一个,switch逻辑也就结束了,不会顺序执行别的case,但是可以使用fallthrough强制执行后面的case代码:



package main  
  
import "fmt"  
  
func main() {  
    /* 定义局部变量 */  
    var grade string = "B"  
    var marks int = 40  
  
    switch marks {  
    case 90:  
        grade = "A"  
    case 80:  
        grade = "B"  
    case 50, 60, 70:  
        grade = "C" //case 后可以由多个数值  
    default:  
        grade = "D"  
    }  
  
    switch {  
    case grade == "A":  
        fmt.Printf("A\n")  
    case grade == "B", grade == "C":  
        fmt.Printf("B\n")  
    case grade == "D":  
        fmt.Printf("D\n")  
    case grade == "F":  
        fmt.Printf("F\n")  
    default:  
        fmt.Printf("low\n")  
    }  
    fmt.Printf("你的等级是 %s\n", grade)  
}  


程序返回:

D  
你的等级是 D

这里我们先通过switch对marks变量进行值判断,在case分支里赋值grade变量,随后又在switch逻辑中对grade做恒等判断,然后输出。

假设需要贯通后续的case,就添加fallthrough关键字:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    switch x := 5; x {  
    default:  
        fmt.Println(x)  
    case 5:  
        x += 10  
        fmt.Println(x)  
        fallthrough  
    case 6:  
        x += 20  
        fmt.Println(x)  
  
    }  
  
}

这里首先进入case5逻辑,x经过运算后变为15,随后贯通进入下一个逻辑,x += 20 逻辑,变为35。

程序返回:

15  
35

需要注意的是,fallthrough应该是某个case的最后一行。如果它出现在中间的某个地方,编译器就会抛出错误。

循环结构之遍历for

for关键字可以用来重复执行某一段代码,在Python中,遍历方式有三种:for 、 while 和 do while 。但是Go lang只为我们提供了一种:for:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    num := 1  
    for num < 3 {  
        fmt.Println(num)  
        num++  
    }  
  
}

程序返回:

1  
2

这里是但条件循环,如果满足条件,for代码块的逻辑会重置执行。

我们还可以为遍历添加额外的表达式逻辑,比如初始化控制变量,在整个循环生命周期内,只执行一次;设置循环控制条件,该表达式值为 true 时循环,值为 false 时结束循环;每次循环完都会执行此表达式,可以利用其让控制变量增量或减量:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
    for num := 0; num < 4; num++ {  
        fmt.Println(num)  
    }  
  
}

程序返回:

0  
1  
2  
3

需要注意的是,在for关键字中声明的变量,也只在for的代码块中有效,因为和Python不同,go lang有严格的块作用域限制。

在 Go lang中遍历一个可迭代的对象一般使用 for-range 语句实现,其中 range 后面可以接数组、切片、字符串等, range 会返回两个值,第一个是索引值,第二个是数据值:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
  
    str := "123456789"  
    for index, value := range str {  
        fmt.Printf("index %d, value %c\n", index, value)  
    }  
  
}

程序返回:

index 0, value 1  
index 1, value 2  
index 2, value 3  
index 3, value 4  
index 4, value 5  
index 5, value 6  
index 6, value 7  
index 7, value 8  
index 8, value 9

如果for关键字后面没有表单式,就是死循环:

package main  
  
import (  
    "fmt"  
)  
  
func main() {  
  
    num := 1  
  
    for {  
  
        fmt.Println(num)  
        num++  
  
        if num > 3 {  
            break  
        }  
  
    }  
  
}

程序返回:

1  
2  
3

是的,我们当然可以使用break关键字来中断循环。

但需要注意的是,break只能终端当前循环,不能终端外部循环:

package main  
  
import "fmt"  
  
func main() {  
    /* 定义局部变量 */  
    var i, j int  
    for i = 2; i < 10; i++ {  
        for j = 2; j <= (i / j); j++ {  
            if i%j == 0 {  
                break // 如果发现因子,则不是素数  
            }  
        }  
        if j > (i / j) {  
            fmt.Printf("%d  是素数\n", i)  
        }  
    }  
}

程序返回:

2  是素数  
3  是素数  
5  是素数  
7  是素数

和Python一样,Go lang也具备continue关键字,continue 语句用来跳出 for 循环中的当前循环:

package main  
  
import "fmt"  
  
func main() {  
  
    for num := 1; num <= 10; num++ {  
        if num%2 == 0 {  
            continue  
        }  
        fmt.Println(num)  
    }  
  
}

程序返回:

1  
3  
5  
7  
9

在 continue 语句后的所有的 for 循环语句都不会在本次循环中执行,执行完 continue 语句后将会继续执行一下次循环。这样我们就可以跳过偶数,直接打印出 10 以内的奇数。

goto 无条件跳转

使用goto关键字可以直接跳到下一步要执行的标签代码:

package main  
  
import "fmt"  
  
func main() {  
  
    for x := 0; x < 10; x++ {  
  
        for y := 0; y < 10; y++ {  
  
            if y == 2 {  
                // 跳转到标签  
                goto breakHere  
            }  
  
        }  
    }  
  
    // 手动返回, 避免执行进入标签  
    return  
  
    // 标签  
breakHere:  
    fmt.Println("done")  
}

程序返回:

done

需要注意的是,goto关键字与标签之间不能有变量声明,否则编译错误。

结语

和Python和Ruby相比,整体上,在流程结构控制环节,Go lang表现出了极大的克制,语法上删繁就简, 把动态语言那些桀骜不驯的语法糖压制成行文工整的诗,这样的好处是对初学者极为友好,没有太多规范需要记忆,大道至简,大巧不工。我们可以吐槽它没有while或者是do while,亦或者是lambda表达式等可以炫技的资本,但,那又如何呢?就像乔帮主在聚贤庄力战群雄,大杀四方,所倚重的不过是一套普普通通的太祖长拳,Go lang亦如此,务实胜过炫技,简单未必普通。

相关文章
|
3天前
|
监控 算法 Go
Golang深入浅出之-Go语言中的服务熔断、降级与限流策略
【5月更文挑战第4天】本文探讨了分布式系统中保障稳定性的重要策略:服务熔断、降级和限流。服务熔断通过快速失败和暂停故障服务调用来保护系统;服务降级在压力大时提供有限功能以保持整体可用性;限流控制访问频率,防止过载。文中列举了常见问题、解决方案,并提供了Go语言实现示例。合理应用这些策略能增强系统韧性和可用性。
52 0
|
3天前
|
JavaScript 前端开发 Go
Go语言的入门学习
【4月更文挑战第7天】Go语言,通常称为Golang,是由Google设计并开发的一种编程语言,它于2009年公开发布。Go的设计团队主要包括Robert Griesemer、Rob Pike和Ken Thompson,这三位都是计算机科学和软件工程领域的杰出人物。
17 1
|
3天前
|
分布式计算 Java Go
Golang深入浅出之-Go语言中的分布式计算框架Apache Beam
【5月更文挑战第6天】Apache Beam是一个统一的编程模型,适用于批处理和流处理,主要支持Java和Python,但也提供实验性的Go SDK。Go SDK的基本概念包括`PTransform`、`PCollection`和`Pipeline`。在使用中,需注意类型转换、窗口和触发器配置、资源管理和错误处理。尽管Go SDK文档有限,生态系统尚不成熟,且性能可能不高,但它仍为分布式计算提供了可移植的解决方案。通过理解和掌握Beam模型,开发者能编写高效的数据处理程序。
140 1
|
3天前
|
缓存 测试技术 持续交付
Golang深入浅出之-Go语言中的持续集成与持续部署(CI/CD)
【5月更文挑战第5天】本文介绍了Go语言项目中的CI/CD实践,包括持续集成与持续部署的基础知识,常见问题及解决策略。测试覆盖不足、版本不一致和构建时间过长是主要问题,可通过全面测试、统一依赖管理和利用缓存优化。文中还提供了使用GitHub Actions进行自动化测试和部署的示例,强调了持续优化CI/CD流程以适应项目需求的重要性。
54 1
|
3天前
|
Kubernetes Cloud Native Go
Golang深入浅出之-Go语言中的云原生开发:Kubernetes与Docker
【5月更文挑战第5天】本文探讨了Go语言在云原生开发中的应用,特别是在Kubernetes和Docker中的使用。Docker利用Go语言的性能和跨平台能力编写Dockerfile和构建镜像。Kubernetes,主要由Go语言编写,提供了方便的客户端库与集群交互。文章列举了Dockerfile编写、Kubernetes资源定义和服务发现的常见问题及解决方案,并给出了Go语言构建Docker镜像和与Kubernetes交互的代码示例。通过掌握这些技巧,开发者能更高效地进行云原生应用开发。
58 1
|
3天前
|
负载均衡 监控 Go
Golang深入浅出之-Go语言中的服务网格(Service Mesh)原理与应用
【5月更文挑战第5天】服务网格是处理服务间通信的基础设施层,常由数据平面(代理,如Envoy)和控制平面(管理配置)组成。本文讨论了服务发现、负载均衡和追踪等常见问题及其解决方案,并展示了使用Go语言实现Envoy sidecar配置的例子,强调Go语言在构建服务网格中的优势。服务网格能提升微服务的管理和可观测性,正确应对问题能构建更健壮的分布式系统。
30 1
|
3天前
|
消息中间件 Go API
Golang深入浅出之-Go语言中的微服务架构设计与实践
【5月更文挑战第4天】本文探讨了Go语言在微服务架构中的应用,强调了单一职责、标准化API、服务自治和容错设计等原则。同时,指出了过度拆分、服务通信复杂性、数据一致性和部署复杂性等常见问题,并提出了DDD拆分、使用成熟框架、事件驱动和配置管理与CI/CD的解决方案。文中还提供了使用Gin构建HTTP服务和gRPC进行服务间通信的示例。
29 0
|
3天前
|
Prometheus 监控 Cloud Native
Golang深入浅出之-Go语言中的分布式追踪与监控系统集成
【5月更文挑战第4天】本文探讨了Go语言中分布式追踪与监控的重要性,包括追踪的三个核心组件和监控系统集成。常见问题有追踪数据丢失、性能开销和监控指标不当。解决策略涉及使用OpenTracing或OpenTelemetry协议、采样策略以及聚焦关键指标。文中提供了OpenTelemetry和Prometheus的Go代码示例,强调全面可观测性对微服务架构的意义,并提示选择合适工具和策略以确保系统稳定高效。
36 5
|
3天前
|
负载均衡 算法 Go
Golang深入浅出之-Go语言中的服务注册与发现机制
【5月更文挑战第4天】本文探讨了Go语言中服务注册与发现的关键原理和实践,包括服务注册、心跳机制、一致性问题和负载均衡策略。示例代码演示了使用Consul进行服务注册和客户端发现服务的实现。在实际应用中,需要解决心跳失效、注册信息一致性和服务负载均衡等问题,以确保微服务架构的稳定性和效率。
22 3
|
3天前
|
前端开发 Go
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式
【5月更文挑战第3天】Go语言通过goroutines和channels实现异步编程,虽无内置Future/Promise,但可借助其特性模拟。本文探讨了如何使用channel实现Future模式,提供了异步获取URL内容长度的示例,并警示了Channel泄漏、错误处理和并发控制等常见问题。为避免这些问题,建议显式关闭channel、使用context.Context、并发控制机制及有效传播错误。理解并应用这些技巧能提升Go语言异步编程的效率和健壮性。
30 5
Golang深入浅出之-Go语言中的异步编程与Future/Promise模式