Go语言编程 学习笔记整理 第2章 顺序编程 后半部分
1.流程控制
1.1 条件语句
if a < 5 { return 0
} else { return 1
}
注意:在有返回值的函数中,不允许将“最终的”return语句包含在if...else...结构中, 否则会编译失败!!!
func example(x int) int { if x == 0 { return 5 } else { return x }
}// 编译失败的原因:Go编译器无法找到终止该函数的return语句
1.2 选择语句
switch i { case 0: fmt.Printf("0") case 1: fmt.Printf("1") case 2: fallthrough case 3: fmt.Printf("3") case 4, 5, 6: fmt.Printf("4, 5, 6") default: fmt.Printf("Default")
}
运行上面的案例,将会得到如下结果: i = 0 时,输出 0 ; i = 1 时,输出 1 ; i = 2 时,输出 3 ; i = 3 时,输出 3 ; i = 4 时,输出 4, 5, 6 ; i = 5 时,输出 4, 5, 6 ; i = 6 时,输出 4, 5, 6 ; i = 其他任意值时,输出 Default 。
比较有意思的是,switch后面的表达式甚至不是必需的,比如下面的例子:
switch { case 0 <= Num && Num <= 3: fmt.Printf("0-3") case 4 <= Num && Num <= 6: fmt.Printf("4-6") case 7 <= Num && Num <= 9: fmt.Printf("7-9")
}
- 只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case
- 可以不设定switch之后的条件表达式,在此种情况下,整个switch结构与多个 if...else...的逻辑作用等同
- 在条件表达式中也支持多重赋值
func ForCase() {sum := 0for i := 0; i < 10; i++ {sum += i}fmt.Println(sum) // 45// 在条件表达式中也支持多重赋值,如下表示:a := []int{1, 2, 3, 4, 5, 6}for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {a[i], a[j] = a[j], a[i]}fmt.Println(a) // [6 5 4 3 2 1]
} 另外,Go语言的for循环同样支持continue和break来控制循环,但是它提供了一个更加高级的break,可以选择中断哪一个循环,如下例子:
for j := 0; j < 5; j++ { for i := 0; i < 10; i++ { if i > 5 { break JLoop } fmt.Println(i) }
}
JLoop: - 在Go中,函数的基本组成为:关键字func、函数名、参数列表、返回值、函数体和返回语句
package mainimport ("fmt"
)
import "errors"func Add(a int, b int) (ret int, err error) {if a < 0 || b < 0 { // 假设这个函数只支持两个非负数字的加法err = errors.New("Should be non-negative numbers!")return}return a + b, nil // 支持多重返回值
}func main() {res, err := _case.Add(1, 2)if err != nil {return}fmt.Println(res)
} func Add(a, b int)(ret int, err error) { // ...
} func Add(a, b int) int { // ...
} 2.2 函数调用
import "mymath"// 假设Add被放在一个叫mymath的包中// ...
c := mymath.Add(1, 2) - 小写字母开头的函数只在本包内可见,大写字母开头的函数才能被其他包使用
- 这个规则也适用于类型和变量的可见性
func myfunc(args ...int) { for _, arg := range args { fmt.Println(arg) }
}// 这段代码的意思是,函数myfunc()接受不定数量的参数,这些参数的类型全部是int,
// 所以它可以用如下方式调用:myfunc(2, 3, 4)
myfunc(1, 3, 7, 13) 形如...type格式的类型只能作为函数的参数类型存在,并且必须是最后一个参数
它是一 个语法糖(syntactic sugar),即这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说,使用语法糖能够增加程序的可读性,从而减少程序出错的机会。
从内部实现机理来说说,类型...type本质上是一个数组切片,也就是[]type,这也是为什么上面的参数args可以用for循环来获得每个传入的参数
假如没有...type这样的语法糖,开发者将不得不这么写:
func myfunc2(args []int) { for _, arg := range args { fmt.Println(arg) }
}
myfunc2([]int{1, 3, 7, 13}) package mainimport ("fmt"
)func processFunc(args ...int) {for i, _ := range args {args[i] += 1}fmt.Println(args)
}func myfunc(args ...int) {// 按照原样传递processFunc(args...)// 传递片段,实际上任意的int slice都可以传进去processFunc(args[1:]...)
}func main() {myfunc(2, 3, 4)
}
![]()
(3)任意类型的不定参数
func Printf(format string, args ...interface{}) { // ...
} 用interface{}传递任意类型数据是Go语言的惯例用法。使用interface{}仍然是类型安全的,和C/C++不太一样
func MyPrintf(args ...interface{}) {for _, arg := range args {switch arg.(type) {case int:fmt.Println(arg, "is an int value.")case string:fmt.Println(arg, "is a string value.")case int64:fmt.Println(arg, "is an int64 value.")default:fmt.Println(arg, "is an unknown type.")}}
}func main() {var v1 int = 1var v2 int64 = 234var v3 string = "heheda"var v4 float32 = 1.234_case.MyPrintf(v1, v2, v3, v4)
} 
(4)多返回值
与C、C++和Java等开发语言的一个极大不同在于,Go语言的函数或者成员的方法可以有多个返回值,这个特性能够让我们写出比其他语言更优雅,更简洁的代码。
比如File.Read()函数就可以同时返回读取的字节数和错误信息
如果读取文件成功,则返回值中的n为读取的字节数,err为nil,否则err为具体的出错信息:
func (file *File) Read(b []byte) (n int, err Error) 同样,从上面的方法原型可以看到,我们还可以给返回值命名,就像函数的输入参数一样。
- 返回值被命名之后,它们的值在函数开始的时候被自动初始化为空
- 在函数中执行不带任何参数的return语句时,会返回对应的返回值变量的值
Go语言并不需要强制命名返回值,但是命名后的返回值可以让代码更清晰,可读性更强,同时也可用于文档
如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线"_"来跳过这个返回值,比如下面的代码表示调用者在读文件的时候不想关心Read()函数返回的错误码:
n, _ := f.Read(buf) (5)匿名函数与闭包
① 匿名函数是指不需要定义函数名的一种函数实现方式,匿名函数由一个不带函数名的函数声明和函数体组成,如下所示:
func NMFunc() {f := func(x, y int) int {return x + y}fmt.Println(f(1, 2)) // 输出: 3// 创建一个通道replyChan := make(chan int)// 启动一个新的 Goroutine,执行匿名函数,并向通道发送数据go func(ch chan int) {ch <- 42}(replyChan) // 花括号后直接跟参数列表,表示调用// 从通道接收数据ack := <-replyChan// 打印接收到的数据fmt.Println(ack) // 输出: 42// 关闭通道close(replyChan)
}
②闭包:Go的匿名函数是一个闭包
基本概念:闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含 在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环境(作用域)。
闭包的价值:在于可以作为函数对象或者匿名函数
Go语言中的闭包:Go语言中的闭包同样会引用到函数外的变量,闭包的实现确保只要闭包还被使用,那么被闭包引用的变量会一直存在
closure.go
package main
import ( "fmt"
)
func main() { var j int = 5 a := func()(func()) { var i int = 10 return func() { fmt.Printf("i, j: %d, %d\n", i, j) } }() a() j *= 2 a()
} 上述例子的执行结果是:i, j: 10, 5i, j: 10, 10
type error interface { Error() string
} func Foo(param int)(n int, err error) { // ...
} n, err := Foo(0)
if err != nil { // 错误处理
} else { // 使用返回值n
} 自定义的error类型
步骤一:定义一个用于承载错误信息的类型
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error()
} 当然,这里是一个完整的例子展示了如何定义一个自定义的 PathError 类型,并在文件操作中使用这个类型在出错时进行错误处理和信息提取
package mainimport ("fmt""os"
)// PathError 自定义错误类型
type PathError struct {Op stringPath stringErr error
}// 实现 error 接口的 Error 方法
func (e *PathError) Error() string {return e.Op + " " + e.Path + ": " + e.Err.Error()
}// 函数用来模拟文件操作,并返回一个自定义的 PathError 错误
func simulateFileOperation() error {// 尝试获取文件信息,这里故意对一个不存在的文件操作_, err := os.Stat("a.txt")if err != nil {// 返回自定义的 PathError 错误return &PathError{Op: "stat",Path: "a.txt",Err: err,}}return nil
}func main() {// 调用模拟文件操作的函数err := simulateFileOperation()if err != nil {// 把错误断言为 *PathError 类型if e, ok := err.(*PathError); ok && e.Err != nil {// 获取 PathError 类型变量 e 中的其他信息并处理fmt.Printf("Operation: %s\n", e.Op)fmt.Printf("Path: %s\n", e.Path)fmt.Printf("Error: %s\n", e.Err)fmt.Printf("Full Error: %s\n", e.Error())} else {// 其他类型的错误fmt.Println(err)}} else {// 文件操作成功fmt.Println("File operation succeeded")}
} 在这个示例中:
① 定义了一个PathError类型,这个类型有Op(操作)、Path(路径)和Err(底层错误)三个字段
② 实现了PathError类型的Error方法,以满足error接口
③ 编写了一个simulateFileOperation函数,这个函数尝试获取一个不存在的文件的状态,并返回一个自定义的PathError错误
④ 在main函数中,调用simulateFileOperation函数,接收并处理这个自定义错误
这样,当你运行这个示例时,如果文件a.txt不存在,会输出:
Operation: stat
Path: a.txt
Error: stat a.txt: no such file or directory
Full Error: stat a.txt: stat a.txt: no such file or directory 这个示例展示了如何自定义错误类型并在程序中使用它来进行错误处理和信息提取
这就是Go中error类型的使用方法,与其他语言中的异常相比,Go的处理相对比较直观,简单
2.5 defer
- 关键字defer是Go语言引入的一个非常有意思的特性
相关文章:
Go语言编程 学习笔记整理 第2章 顺序编程 后半部分
1.流程控制 1.1 条件语句 if a < 5 { return 0 } else { return 1 } 注意:在有返回值的函数中,不允许将“最终的”return语句包含在if...else...结构中, 否则会编译失败!!! func example(x int) i…...
美团后端二面
美团后端二面 ……………………………… 两道场景 一道 数字转中文读法(1000-》一千) 0八股0自我介绍 反问 “您觉得我能过吗?” “这个需要横行对比之后才能有结果” ……………………………… 什么时候到岗 场景题 1 假设我有一个…...
学懂C语言(十六):对C语言作用域规则 局部变量、全局变量的认识
一、C 作用域规则 任何一种编程中,作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问。C 语言中有三个地方可以声明变量: 局部变量:在函数或块内部全局变量:在所有函数外部形式参数:在函数…...
关于TS(typescript)的理论知识
关于TS(typescript)的理论知识 TypeScript 是一种由微软开发的开源编程语言,它是 JavaScript 的一个超集,添加了可选的静态类型和基于类的面向对象编程。TypeScript 最终会被编译成纯 JavaScript 代码,以便在任何支持 …...
【OpenCV C++20 学习笔记】基本图像容器——Mat
【OpenCV C20 学习笔记】基本图像容器——Mat 概述Mat内部结构引用计数机制颜色数据格式 显式创建Mat对象使用cv::Mat::Mat构造函数矩阵的数据项 使用数组进行初始化的构造函数cv::Mat::create函数MATLAB风格的初始化小型矩阵通过复制创建Mat对象 Mat对象的输出其他普通数据项的…...
枚举单例是怎么保证线程安全和防止反射的
枚举单例在Java中具有天然的线程安全性和防止反射攻击的特性,这是由于Java对枚举类型的特殊处理方式。以下是详细解释: 1. 线程安全性 Java 枚举类的特性 类加载机制:枚举类型在Java中是特殊的类,由JVM保证其线程安全性。枚举类…...
传知代码-智慧医疗:纹理特征VS卷积特征(论文复现)
代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 论文链接:https://www.sciencedirect.com/science/article/abs/pii/S1076633223003537?__cf_chl_rt_tkJ9Aipfxyk5d.leu48P20ePFNd4B2aunaSmzVpXCg.7g-1721292386-0.0.1.1-6249 论文概述 今天我们把视线…...
数据结构中的八大金刚--------八大排序算法
目录 引言 一:InsertSort(直接插入排序) 二:ShellSort(希尔排序) 三:BubbleSort(冒泡排序) 四: HeapSort(堆排序) 五:SelectSort(直接选择排序) 六:QuickSort(快速排序) 1.Hoare版本 2.前后指针版本 …...
ACC2.【C语言】经验积累 栈区简单剖析
int main() {int i0;int arr[10]{1,2,3,4,5,6,7,8,9,10};for (i0;i<12;i){arr[i]0;printf("A");}return 0; } 执行后无限打印A 在VS2022,X86,Debug环境下,用监视后,原因是arr[12]的地址与i的地址重合(数组越界&…...
c# 索引器
索引器(Indexer)允许你像访问数组一样,通过索引访问对象的属性或数据。索引器的主要用途是在对象内部封装复杂的数据结构,使得数据访问更加直观。下面是关于 C# 索引器的详细解释及示例: 基本语法 索引器的语法类似于…...
低代码如何加速数字化转型
数字化转型,正日益决定企业成功的关键。这里的一个关键因素是它可以以更快的速度和质量来实施技术计划。在当今瞬息万变的商业环境中,战略性地采用低代码平台对于旨在加快上市时间、增强业务敏捷性和促进跨团队无缝协作的首席技术官来说至关重要。日益增…...
Pytest进阶之fixture的使用(超详细)
目录 Fixture定义 Fixture使用方式 作为参数使用 Fixture间相互调用(作为参数调用) 作为conftest.py文件传入 Fixture作用范围Scope function class module session Fixture中params和ids Fixture中autouse Fixture中Name 总结 pytest fixture 是一种用来管理测试…...
GitHub 详解教程
1. 引言 GitHub 是一个用于版本控制和协作的代码托管平台,基于 Git 构建。它提供了强大的功能,使开发者可以轻松管理代码、追踪问题、进行代码审查和协作开发。 2. Git 与 GitHub 的区别 Git 是一个分布式版本控制系统,用于跟踪文件的更改…...
边界网关IPSEC VPN实验
拓扑: 实验要求:通过IPSEC VPN能够使PC2通过网络访问PC3 将整个路线分为三段 IPSEC配置在FW1和FW2上,在FW1与FW2之间建立隧道,能够传递IKE(UDP500)和ESP数据包,然后在FW1与PC2之间能够流通数据…...
力扣高频SQL 50题(基础版)第六题
文章目录 1378. 使用唯一标识码替换员工ID题目说明思路分析实现过程结果截图总结 1378. 使用唯一标识码替换员工ID 题目说明 Employees 表: ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | ------…...
在一个事物方法中开启新事物,完成对数据库的修改
在Java中,使用Transactional注解来管理事务非常常见。但是,在一个已经标记为Transactional的方法内部调用另一个也标记了Transactional的方法时,如果不正确处理,可能会导致一些意料之外的行为。这是因为默认情况下,Spr…...
ffmpeg的vignetting filter
vignetting filter是暗角过滤器 vignetting filter在官网是vignette。但是我查了一下,vignetting应该是正确的表达,vignette是什么鬼? 官网参数 官书参数 参数解释 angle,x0,y0可以使用表达式。 angle:不知道什么意思…...
商场导航系统:从电子地图到AR导航,提升顾客体验与运营效率的智能解决方案
商场是集娱乐、休闲、社交于一体的综合性消费空间,随着商场规模的不断扩大和布局的日益复杂,顾客在享受丰富选择的同时,也面临着寻路难、店铺曝光率低以及商场管理效率低下等挑战。商场导航系统作为提升购物体验的关键因素,其重要…...
vue3中父子组件的双向绑定defineModel详细使用方法
文章目录 一、defineProps() 和 defineEmits()二、defineModel() 的双向绑定2.1、基础示例2.2、定义类型2.3、声明prop名称2.4、其他声明2.5、绑定多个值2.6、修饰符和转换器2.7、修饰符串联 一、defineProps() 和 defineEmits() 组件之间通讯,通过 props 和 emits…...
耳机、音响UWB传输数据模组,飞睿智能低延迟、高速率超宽带uwb模块技术音频应用
在数字化浪潮席卷全球的今天,无线通信技术日新月异,其中超宽带(Ultra-Wideband,简称UWB)技术以其独特的优势,正逐步成为无线传输领域的新星。本文将深入探讨飞睿智能UWB传输数据模组在音频应用中的创新应用…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
