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传输数据模组在音频应用中的创新应用…...

webpack配置报错:Invalid options object.
前言: 今天在使用webpack进行项目配置的时候,运行之后终端报错:Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. - options has an unknown property inline. Thes…...

Java 并发编程:一文了解 Java 内存模型(处理器优化、指令重排序与内存屏障的深层解析)
大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 022 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进…...

谷粒商城实战笔记-64-商品服务-API-品牌管理-OSS前后联调测试上传
文章目录 1,拷贝文件到前端工程2,局部修改3,在品牌编辑界面使用上传组件4,OSS配置允许跨域5,测试multiUpload.vue完整代码singleUpload.vue完整代码policy.js代码 在Web应用开发中,文件上传是一项非常常见的…...

Springboot 开发之 RestTemplate 简介
一、什么是RestTemplate RestTemplate 是Spring框架提供的一个用于应用中调用REST服务的类。它简化了与HTTP服务的通信,统一了RESTFul的标准,并封装了HTTP连接,我们只需要传入URL及其返回值类型即可。RestTemplate的设计原则与许多其他Sprin…...

Django transaction.atomic()事务处理
在Django中,transaction.atomic()是一个上下文管理器,它会自动开始一个事务,并在代码块执行完毕后提交事务。如果在代码块中抛出异常,事务将被自动回滚,确保数据库的一致性和完整性。 在实际应用中,你可能需…...

2024.07-电视版免费影视App推荐和猫影视catvod、TVBox源(最新接口地址)
文章目录 电视版免费影视App推荐精选列表(2024.07可用筛选列表):2024.07可用筛选列表,盲盒资源打包合集下载安装说明真的是盲盒? 猫影视catvod、TVBoxTVBox源推荐可用列表目前不可用列表(前缀为错误状态码&…...

【Python】 基于Q-learning 强化学习的贪吃蛇游戏(源码+论文)【独一无二】
👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…...

谷粒商城实战笔记-44-前端基础-Vue-整合ElementUI快速开发/设置模板代码
文章目录 一,安装导入ElementUI1,安装 element-ui2,导入 element-ui 二,ElementUI 实战1,将 App.vue 改为 element-ui 中的后台布局2,开发导航栏2.1 开发MyTable组件2.2 注册路由2.3 改造App.vue2.4 新增左…...
Android adb shell ps进程查找以及kill
Android adb shell ps进程查找以及kill 列出当前Android手机上运行的所有进程信息如PID等: adb shell ps 但是这样会列出一大堆进程信息,不便于定向查阅,可以使用关键词查找: adb shell "ps | grep 关键词" 关键词查…...

[OJ]水位线问题,1.采用回溯法(深度优先遍历求解)2.采用广度优先遍历求解
1.深度优先遍历 使用回溯法,深度优先遍历利用栈先进后出的特点,在加水控制水量失败时, 回到最近一次可对水进行加水与否的位置1.对于给定水量k,是否在[l,r]之间, 是:是否加水(加水y,用掉x,是否在[l,r]之间)(不加水y,用掉x,是否在[l,r]之间)先尝试加水,如…...