Go后端开发 -- 条件、循环语句 defer语句

news2024/11/21 0:36:26

Go后端开发 – 条件、循环语句 && defer语句

文章目录

  • Go后端开发 -- 条件、循环语句 && defer语句
  • 一、条件语句
    • 1.if ... else 语句
    • 2.switch语句
    • 3.select语句
  • 二、循环语句
    • 1.for循环
  • 三、defer语句
    • 1.defer语句的作用
    • 2.defer和return的先后顺序
    • 3.recover错误拦截


一、条件语句

1.if … else 语句

语法:

if 布尔表达式 {
   /* 在布尔表达式为 true 时执行 */
} else {
  /* 在布尔表达式为 false 时执行 */
}

与C的if … else语句的区别是条件不用加括号
实例

package main

import "fmt"

func main() {
   /* 局部变量定义 */
   var a int = 100;
 
   /* 判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" );
   } else {
       /* 如果条件为 false 则执行以下语句 */
       fmt.Printf("a 不小于 20\n" );
   }
   fmt.Printf("a 的值为 : %d\n", a);
}

2.switch语句

语法:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
  • switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break
  • switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough
  • 变量 var1 可以是任何类型,而 val1 和 val2 则可以是同类型的任意值。类型不被局限于常量或整数,但必须是相同的类型;或者最终结果为相同类型的表达式
  • 可以同时测试多个可能符合条件的值,使用逗号分割它们,例如:case val1, val2, val3
  • switch语句可以不在switch开头确定判断的条件,可以在case中进行条件判断;

实例:

package Switch

import "fmt"

func Switch() {
	grade := 'B'
	marks := 90

	switch marks {
	case 90:
		grade = 'A'
	case 80:
		grade = 'B'
	case 70, 60, 50:
		grade = 'C'
	default:
		grade = 'D'
	}

	switch {
	case grade == 'A':
		fmt.Println("优秀")
	case grade == 'B':
		fmt.Println("良好")
	case grade == 'C':
		fmt.Println("及格")
	default:
		fmt.Println("不及格")
	}

	fmt.Println("你的等级是:", grade)
}

在这里插入图片描述

  • switch语句还可以被用于type-switch来判断某个 interface 变量中实际存储的变量类型。

Type Switch 语法格式如下

switch x.(type){
    case type:
       statement(s);      
    case type:
       statement(s); 
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s);
}

实例:

package Switch

import "fmt"

func TypeSwitch() {
	var x interface{}

	switch i := x.(type) {
	case nil:
		fmt.Printf("x的类型: %T\n", i)
	case int:
		fmt.Println("x是int型")
	case float64:
		fmt.Println("x是float64型")
	case func(int) float64:
		fmt.Println("x是func(int)型")
	case bool, string:
		fmt.Println("x是bool或string型")
	default:
		fmt.Println("未知型")
	}
}

在这里插入图片描述

  • fallthrough
    使用 fallthrough 会强制执行后面的 case 语句,包括defaultfallthrough 不会判断下一条case的表达式结果是否为 true。
  • fallthrough只会强制执行后面一条case语句,而不是后面的全部;

实例1:

package Switch

import "fmt"

func Fallthrough() {
	switch {
	case false:
		fmt.Println("1.case条件语句为false")
		fallthrough
	case true:
		fmt.Println("2.case条件语句为true")
		fallthrough
	case false:
		fmt.Println("3.case条件语句为false")
		fallthrough
	case true:
		fmt.Println("4.case条件语句为true")
		fallthrough
	case false:
		fmt.Println("5.case条件语句为false")
		fallthrough
	default:
		fmt.Println("6.默认case")
	}
}

在这里插入图片描述
实例2:

package Switch

import "fmt"

func Fallthrough() {
	switch {
	case false:
		fmt.Println("1.case条件语句为false")
		fallthrough
	case true:
		fmt.Println("2.case条件语句为true")
		fallthrough
	case false:
		fmt.Println("3.case条件语句为false")
		//fallthrough
	case true:
		fmt.Println("4.case条件语句为true")
		//fallthrough
	case false:
		fmt.Println("5.case条件语句为false")
		//fallthrough
	default:
		fmt.Println("6.默认case")
	}
}

在这里插入图片描述

3.select语句

select 是 Go 中的一个控制结构,类似于 switch 语句。

  • select 语句只能用于通道操作每个 case 必须是一个通道操作,要么是发送要么是接收。
  • select 语句会监听所有指定的通道上的操作,一旦其中一个通道准备好就会执行相应的代码块。
  • 如果多个通道都准备好,那么 select 语句会随机选择一个通道执行。如果所有通道都没有准备好,那么执行 default 块中的代码。

Go 编程语言中 select 语句的语法如下:

select {
  case <- channel1:
    // 执行的代码
  case value := <- channel2:
    // 执行的代码
  case channel3 <- value:
    // 执行的代码

    // 你可以定义任意数量的 case

  default:
    // 所有通道都没有准备好,执行的代码
}
  • 每个 case 都必须是一个通道
  • 所有 channel 表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通道可以进行,它就执行,其他被忽略。
  • 如果有多个 case 都可以运行,select 会随机公平地选出一个执行,其他不会执行。
    否则:
    • 如果有 default 子句,则执行该语句。
    • 如果没有 default 子句,select 将阻塞,直到某个通道 可以运行;Go 不会重新对 channel 或值进行求值。

实例1:

package Select

import (
	"fmt"
	"time"
)

func Select() {
	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		c1 <- "one"
	}()
	go func() {
		time.Sleep(2 * time.Second)
		c2 <- "two"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}
}

在这里插入图片描述

  • 以上实例中,我们创建了两个通道 c1 和 c2。
    select 语句等待两个通道的数据。如果接收到 c1 的数据,就会打印 “received one”;如果接收到 c2 的数据,就会打印 “received two”。

实例2:

package Select

import (
	"fmt"
	"time"
)

func Select1() {
	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		c1 <- "one"
	}()
	go func() {
		time.Sleep(2 * time.Second)
		c2 <- "two"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}
}

func Select2() {
	// 定义两个通道
	ch1 := make(chan string)
	ch2 := make(chan string)

	// 启动两个 goroutine,分别从两个通道中获取数据
	go func() {
		for {
			ch1 <- "from 1"
		}
	}()
	go func() {
		for {
			ch2 <- "from 2"
		}
	}()

	// 使用 select 语句非阻塞地从两个通道中获取数据
	for {
		select {
		case msg1 := <-ch1:
			fmt.Println(msg1)
		case msg2 := <-ch2:
			fmt.Println(msg2)
		default:
			// 如果两个通道都没有可用的数据,则执行这里的语句
			fmt.Println("no message received")
		}
	}
}

在这里插入图片描述

  • 以上实例中,我们定义了两个通道,并启动了两个协程(Goroutine)从这两个通道中获取数据。在 main 函数中,我们使用 select 语句在这两个通道中进行非阻塞的选择,如果两个通道都没有可用的数据,就执行 default 子句中的语句。
    以上实例执行后会不断地从两个通道中获取到的数据,当两个通道都没有可用的数据时,会输出 “no message received”。

二、循环语句

1.for循环

for 循环是一个循环控制结构,可以执行指定次数的循环。
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

  • 和 C 语言的 for 一样:
for init; condition; post { }

init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

  • 和 C 的 while 一样:
for condition { }
  • 和 C 的 for(;;) 一样:
for { }
  • for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
    newMap[key] = value
}

以上代码中的 key 和 value 是可以省略。
如果只想读取 key,格式如下:

for key := range oldMap

或者这样:

for key, _ := range oldMap

如果只想读取 value,格式如下:

for _, value := range oldMap

实例1:

package For

import "fmt"

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

在这里插入图片描述

实例2:

package For

import "fmt"

func While() {
	sum := 1

	for sum <= 10 {
		sum += sum
	}
	fmt.Println(sum)
}

在这里插入图片描述

  • 以上实例是将init 和 post参数去掉,相当于是一个while循环

实例3:

package For

import "fmt"

func main() {
   sum := 0
   for {
      sum++ // 无限循环下去
   }
   fmt.Println(sum) // 无法输出
}
  • for后面什么也不跟就是无限循环;

实例4:

package For

import "fmt"

func Range() {
	strings := []string{"google", "runoob"}
	for i, s := range strings {
		fmt.Println(i, s)
	}

	numbers := [6]int{1, 2, 3, 5}
	for i, x := range numbers {
		fmt.Printf("第 %d 位 x 的值 = %d\n", i, x)
	}
}

在这里插入图片描述

  • For-each range 循环可以对字符串、数组、切片等进行迭代输出元素。

实例5:

package For

import "fmt"

func Range() {
	map1 := make(map[int]float32)
    map1[1] = 1.0
    map1[2] = 2.0
    map1[3] = 3.0
    map1[4] = 4.0
   
    // 读取 key 和 value
    for key, value := range map1 {
      fmt.Printf("key is: %d - value is: %f\n", key, value)
    }

    // 读取 key
    for key := range map1 {
      fmt.Printf("key is: %d\n", key)
    }

    // 读取 value
    for _, value := range map1 {
      fmt.Printf("value is: %f\n", value)
    }
}

在这里插入图片描述

  • For-each range也可以读取map中的k和v

三、defer语句

1.defer语句的作用

defer语句被用于预定对一个函数的调用。可以把这类被defer语句调用的函数称为延迟函数。
defer语句会将其后的函数调用推迟到当前所在函数体的生命周期结束后再执行,类似于c++的析构函数。这个特性常用于处理成对的操作,如打开/关闭文件、获取/释放锁、连接/断开连接等确保资源被适当地释放,即使在发生错误或提前返回的情况下也能保证执行。
defer作用:

  • 释放占用的资源
  • 捕捉处理异常
  • 输出日志

如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。
在这里插入图片描述
实例

package Defer

import "fmt"

func Defer() {
	defer fmt.Println("main end1")
	defer fmt.Println("main end2")

	fmt.Println("0")
	fmt.Println("1")
}

在这里插入图片描述

  • defer语句调用的函数会在当前函数体生命周期结束后再出栈执行,多个defer语句调用函数的顺序类似于堆栈,后进先出;

2.defer和return的先后顺序

package Defer

import "fmt"

func deferFunc() int {
	fmt.Println("defer func called...")
	return 0
}

func returnFunc() int {
	fmt.Println("return func caller...")
	return 0
}

func ReturnAndDefer() int {
	defer deferFunc()
	return returnFunc()
}

在这里插入图片描述

  • 由于defer语句会将其后的函数调用推迟到当前所在函数体的生命周期结束后再出栈,而return语句是在}之前的,因此return会先执行,defer再执行;

3.recover错误拦截

运行时panic异常一旦被引发就会导致程序崩溃。

  • Go语言提供了专用于“拦截”运行时panic的内建函数recover它可以是当前的程序从运行时panic的状态中恢复并重新获得流程控制权
  • 注意:recover只有在defer调用的函数中有效。

实例1:

package main

import "fmt"

func recoverFunc(i int) {
	//定义10个元素的数组
	var arr [10]int
	//错误拦截要在产生错误前设置
	//这里使用匿名函数进行错误拦截,在进行defer调用
	//相当于这个匿名函数在recoverFunc的生命周期结束后才被调用
	defer func() {
		//设置recover拦截错误信息
		err := recover()
		//产生panic异常,打印错误信息
		if err != nil {
			fmt.Println(err)
		}
	}()
	//根据函数参数为数组元素赋值
	//如果i的值超过数组下标 会报错误:数组下标越界
	arr[i] = 2
}

func main() {
	recoverFunc(10)
	fmt.Println("程序继续执行...")
}

在这里插入图片描述

  • 在上述实例中,我们定义了一个匿名函数来拦截panic,并用defer去掉用,这个匿名函数会在当前recoverFunc的生命周期结束后进行调用,recoverFunc函数中出现了数组越界的错误,之后被recover()拦截了,程序得以继续执行;

实例2:

package main

import "fmt"

func handlePanic() {
    if r := recover(); r != nil {
        fmt.Println("Recovered:", r)
    }
}

func performTask() {
    defer handlePanic()

    fmt.Println("Performing some task...")
    panic("Oops! Something went wrong!")
    fmt.Println("Task completed.")
}

func main() {
    performTask()
    fmt.Println("Main function continues.")
}

在这里插入图片描述

  • 在以上的实例中,panic函数调用后,异常被引发,当前performTask函数执行结束,defer调用的函数开始出栈,执行handlePanic函数,panic异常引发后,在handlePanic函数中recover拦截了异常,打印出错误信息,并让main函数继续运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1375106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c;它允许在 Spring 应用程序中发布和监听事件。这种机制的主要目的是为了实现解耦&#…

【JaveWeb教程】(19) MySQL数据库开发之 MySQL数据库操作-DML 详细代码示例讲解

目录 3. 数据库操作-DML3.1 增加(insert)3.2 修改(update)3.3 删除(delete)3.4 总结 3. 数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 添加数据&#xff08;INSERT&#xff09;修改数据…

第二百六十回

文章目录 知识回顾示例代码经验总结 我们在上一章回中介绍了通道相关的内容&#xff0c;本章回中将介绍其中的一种通道&#xff1a;MethodChannnel.闲话休提&#xff0c;让我们一起Talk Flutter吧。 知识回顾 我们在上一章回中介绍了通道的概念和作用&#xff0c;并且提到了通…

脱机I/O方式和假脱机系统

提示&#xff1a;在写这个博客的时候小编更加的觉得计算机基础知识的重要性了&#xff0c;而且对计算机的整个发展历程和计算机的底层工作原理特别感兴趣 脱机I/O方式和假脱机系统 一、脱机I/O方式二、假脱机系统1、假脱机技术&#xff08;SPOOLing&#xff0c; simulataneaus …

一日难再晨及时当勉励 date

文章目录 Linux shell 获取更改系统时间默认输入显示时区世界协调时格式化日期更多信息 Linux shell 获取更改系统时间 … note:: 时光只解催人老&#xff0c;不信多情&#xff0c;长恨离亭&#xff0c;泪滴春衫酒易醒。 - 晏殊《采桑子时光只解催人老》date命令可以用来打印…

GPT 商店强势来袭,人人都要有自己的 GPTs

作者&#xff1a;苍何&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;CSDN 2023 年 实力新星&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#xf…

Python学习从0到1 day1 你好 Python

我会在那腥臭腐朽的日子里熠熠生辉 ——24.1.11 1.第一个Python程序 安装python程序,输出第一个程序:你好,世界 print("Hello World"); 2.Python解释器 python解释器,是一个计算机程序,用来翻译python代码,并提交给计算机执行 功能:1.翻译代码 2.提交给计算机…

快速打通 Vue 3(四):标签的 ref 属性与 Vue3 生命周期

很激动进入了 Vue 3 的学习&#xff0c;作为一个已经上线了三年多的框架&#xff0c;很多项目都开始使用 Vue 3 来编写了 这一组文章主要聚焦于 Vue 3 的新技术和新特性 如果想要学习基础的 Vue 语法可以看我专栏中的其他博客 Vue&#xff08;一&#xff09;&#xff1a;Vue 入…

【Unity】Joystick Pack摇杆插件实现锁四向操作

Joystick Pack ​ 简介&#xff1a;一款Unity摇杆插件&#xff0c;非常轻量化 ​ 摇杆移动类型&#xff1a;圆形、横向、竖向 ​ 摇杆类型&#xff1a; Joystick描述Fixed固定位置Floating浮动操纵杆从用户触碰的地方开始&#xff0c;一直固定到触碰被释放。Dynamic动态操纵…

6个Linux进程管理命令

这些命令允许你查看、监视和控制 Linux 系统上运行的进程。这对确定资源使用情况和停止行为不端的程序非常有用。 1. ps – 报告当前进程概览 使用ps&#xff0c;您可以查看当前shell会话正在运行的进程。它打印有关正在运行的程序的有用信息&#xff0c;如进程ID、TTY&#…

使用微信读书高效阅读论文,自带翻译功能。

下面以“向文本到图像扩散模型添加条件控制”&#xff08;Adding Conditional Control to Text-to-Image Diffusion Models&#xff09;这篇论文示例下阅读效果。 论文地址&#xff1a;https://arxiv.org/abs/2302.05543 选择右侧的download PDF, 然后进入论文预览页面&#x…

一、Sharding-JDBC系列01:整合SpringBoot实现分库分表,读写分离

目录 一、概述 二、案例演示-水平分表 (1)、创建springboot工程 (2)、创建数据库和数据表 (3)、application.yaml配置分片规则 (4)、测试数据插入、查询操作 4.1、插入-控制台SQL日志 4.2、查询-控制台SQL日志 三、案例演示-水平分库 (1)、创建数据库和数据表 (2…

延时任务的解决方案

延时任务的解决方案 1.数据库轮询2. JDK的延迟队列3.netty时间轮算法4.使用消息队列 1.数据库轮询 该方案通常是在小型项目中使用&#xff0c;即通过一个线程定时的去扫描数据库&#xff0c;通过订单时间来判断是否有超时的订单&#xff0c;然后进行update或delete等操作 代码示…

蓝桥杯练习题(二)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;二&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

关于CAD导入**地球的一些问题讨论

先上示例: 上图是将北京王佐停车场的红线CAD图导入到图新地球效果,如果看官正是需要这样的效果,那么请你继续往下看,全是干货! 在地球中导入CAD图可以做为电子沙盘。对于工程人来说,是极有帮助的。以前一直用谷歌地球,大约在2020年左右,就被和谐了。当时感觉挺可惜的。…

基于OpenMV与STM32的数据通信项目(代码开源)

前言&#xff1a;本文为手把手教学 OpenMV 与 STM32 的数据通信项目教程&#xff0c;本教程使用 STM32F103C8T6 与 OpenMV 进行操作。 OpenMV 是非常强大的计算机视觉实现工具&#xff0c;自身提供了非常多的视觉项目案例&#xff0c;编程与使用门槛极低。为了进一步增强作品的…

【阅读笔记】Chain of LoRA

一、论文信息 1 论文标题 Chain of LoRA: Efficient Fine-tuning of Language Models via Residual Learning 2 发表刊物 arXiv2023 3 作者团队 Department of Computer Science, Princeton University School of Computer Science and Engineering, Nanyang Technologic…

MySQL基础笔记(3)DML数据操作语句

顾名思义&#xff0c;全称是数据操作语言&#xff0c;用来对数据库中表的数据记录进行增删改操作~ 目录 一.添加数据 1.给指定字段添加数据 2.给全部字段添加数据 3.批量添加数据 二.修改数据 三.删除数据 一.添加数据 1.给指定字段添加数据 insert into 表名 (字段名…

区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测

区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测 目录 区间预测 | Matlab实现CNN-BiLSTM-KDE的卷积双向长短期神经网络结合核密度估计多变量时序区间预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.CNN-BiLSTM-KDE多…

【开源】基于JAVA语言的婚恋交友网站

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 会员管理模块2.3 新闻管理模块2.4 相亲大会管理模块2.5 留言管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 会员信息表3.2.2 新闻表3.2.3 相亲大会表3.2.4 留言表 四、系统展示五、核心代码5.…