Golang教程五(异常处理,泛型,文件操作)

目录

一、异常处理

错误处理与异常区分

Panic 与 Recover

使用原则

二、泛型

泛型函数

 泛型结构体

泛型切片

泛型Map

三、文件操作

1.基础io

Reader interface

Writer interface

Seek interface

Close interface

文件打开模块

1.文件读取

一次性读取

获取当前go文件的路径

分片读

按缓冲读

按行读

光标操作

按分割符读

2.文件写入

文件的打开方式

文件的权限

常规写

快速写

缓冲写

3.文件复制

4.目录操作


一、异常处理

Go 语言的异常处理机制与传统的面向对象语言(如 Java、C#)所使用的 try-catch 结构有所不同,它采用了自己独特的设计理念和方法。

错误处理与异常区分

在 Go 中,错误通常用来表示预期可能会发生的运行时问题,如文件未找到、网络请求失败等。这类问题不是程序本身的严重错误,而是程序运行过程中可能遇到的常态。Go 通过返回值(通常是第二个返回值)来传递错误信息,使得函数调用者能够检查并处理这些错误。常见的做法是在函数签名中添加一个 error 类型的返回值,如:

func SomeFunction(arg string) (result int, err error) {// ...if someErrorCondition {return 0, errors.New("An expected error occurred")}// ...
}

调用者需要显式检查返回的 err 是否为 nil 来判断是否发生错误:

result, err := SomeFunction("input")
if err != nil {// Handle the error herelog.Printf("An error occurred: %v", err)
} else {// Use the resultfmt.Println(result)
}

Panic 与 Recover

Panic 是 Go 语言中用于表示异常或不可恢复的错误情况的一种机制。当程序遇到严重的、无法正常处理的问题,如内部逻辑错误、资源耗尽、不兼容的数据状态等,可以主动调用 panic() 函数来触发恐慌。恐慌会立即中断当前 goroutine(协程)的正常执行流程,并开始执行 栈展开(stack unwinding),即逐级回溯当前 goroutine 的调用栈,执行沿途遇到的 defer 语句,直到整个 goroutine 终止。

func dangerousFunction() {if someCriticalCondition {panic("A critical error occurred!")}// ...
}

 Recover 是与 panic 配合使用的另一个关键函数,它用于捕获发生在当前 goroutine 中的恐慌,并允许程序从恐慌状态中恢复过来。recover() 只能在 defer 函数中有效,因为它依赖于栈展开的过程:

func guardedFunction() {defer func() {if r := recover(); r != nil {// Handle the panic herelog.Printf("Recovered from panic: %v", r)// Optionally, re-throw or convert to a regular error}}()dangerousFunction()
}

 在上述例子中,如果 dangerousFunction() 触发了恐慌,defer 语句中的匿名函数会被调用,此时 recover() 返回恐慌值(通常是 interface{} 类型,可以转换为适当的类型进行处理)。如果没有发生恐慌,recover() 返回 nil

使用原则

  • 错误处理 应作为程序常态的一部分,对于可预见的问题使用返回错误的方式处理,鼓励程序员显式检查并适当地处理这些错误。
  • Panic 应仅用于表示程序中的严重错误或不一致性,通常是那些不应该在正常运行时出现的情况,或者在出现时程序无法安全地继续执行的情况。
  • Recover 通常用于特定的错误边界,如服务入口点、重要组件的外部接口等,以防止局部的恐慌导致整个程序崩溃。对于大多数常规业务逻辑,直接让恐慌向上冒泡到顶层,由程序的主 goroutine 或全局的 recovery 机制来处理更为合适。
  • 使用 panic 和 recover 时应保持谨慎,过度使用可能导致代码难以理解和维护。良好的编程实践是尽可能通过返回错误来处理问题,而非频繁引发恐慌。

综上所述,Go 语言通过明确区分错误处理与异常处理,提倡简洁、显式的错误传播机制,并提供 panic 和 recover 作为处理程序运行时严重问题的手段,构建了一套独特的异常处理体系。开发者应遵循这些原则,确保程序在遇到问题时能够优雅、可控地响应。

二、泛型

Go 语言的泛型(Generics)是该语言的一个重要特性,它允许开发者编写具有类型参数的通用代码,从而提高代码的复用性、减少重复,并增强代码的可读性和安全性。Go 语言的泛型设计经过多年的讨论和迭代,在 Go 1.18 版本(2022年3月发布)中正式引入。以下是对 Go 语言泛型的关键概念、基本用法以及设计特点的概述:

泛型函数

如果我们要实现一个对int类型的求和函数

func add(a, b int) int {return a + b
}

但是这样写了之后,如果参数是float类型,就没办法使用了,难道要为每个类型都写一个这样的函数吗?

显然这就不合理

这个时候,泛型就上场了

func add[T int | float64 | int32](a, b T) T {return a + b
}

 泛型结构体

package mainimport ("encoding/json""fmt"
)type Response[T any] struct {Code int    `json:"code"`Msg  string `json:"msg"`Data T      `json:"data"`
}func main() {type User struct {Name string `json:"name"`}type UserInfo struct {Name string `json:"name"`Age  int    `json:"age"`}//user := Response{// Code: 0,// Msg:  "成功",// Data: User{//   Name: "os_lee",// },//}//byteData, _ := json.Marshal(user)//fmt.Println(string(byteData))//userInfo := Response{// Code: 0,// Msg:  "成功",// Data: UserInfo{//   Name: "os_lee",//   Age:  18,// },//}//byteData, _ = json.Marshal(userInfo)//fmt.Println(string(byteData))var userResponse Response[User]json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"os_lee"}}`), &userResponse)fmt.Println(userResponse.Data.Name)var userInfoResponse Response[UserInfo]json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"os_lee","age":18}}`), &userInfoResponse)fmt.Println(userInfoResponse.Data.Name, userInfoResponse.Data.Age)
}

泛型切片

package maintype MySlice[T any] []Tfunc main() {var mySlice MySlice[string]mySlice = append(mySlice, "枫枫")var intSlice MySlice[int]intSlice = append(intSlice, 2)
}

泛型Map

package mainimport "fmt"type MyMap[K string | int, V any] map[K]Vfunc main() {var myMap = make(MyMap[string, string])myMap["name"] = "os_lee"fmt.Println(myMap)
}

三、文件操作

1.基础io

Reader interface

将len(p)个字节读取到p中

type Reader interface {Read(p []byte) (n int, err error)
}

Writer interface

用于将p中的数据写入到对象的数据流中 

type Writer interface {Write(p []byte) (n int, err error)
}

Seek interface

offset是指针移动的偏移量

whence表示指针移动的方式

  • 0 从数据的头部开始移动指针
  • 1 从数据的当前指针位置开始移动指针
  • 2 从数据的尾部移动指针

seek设置下一次读写操作的指针位置,每次的读写操作都是从指针位置开始的

type Seeker interface {Seek(offset int64, whence int) (int64, error)
}

Close interface

关闭文件

type Closer interface {Close() error
}

文件打开模块

	O_RDONLY int = syscall.O_RDONLY // 只读O_WRONLY int = syscall.O_WRONLY // 只写O_RDWR   int = syscall.O_RDWR   // 读写O_APPEND int = syscall.O_APPEND // 追加O_CREATE int = syscall.O_CREAT  // 如果不存在就创建O_EXCL   int = syscall.O_EXCL   // 文件必须不存在O_SYNC   int = syscall.O_SYNC   // 同步ioO_TRUNC  int = syscall.O_TRUNC  // 打开时清空文件

1.文件读取

ioutil.ReadFile(name string) ([]byte, error)
os.ReadFile(name string) ([]byte, error)
os.Open(name string) (file *File, err error)
os.OpenFile(name string, flag int, perm FileMode) (*File, error)

一次性读取

package mainimport ("fmt""os"
)func main() {bs, err := os.ReadFile("./test.txt")if err != nil {fmt.Printf("Read file error: %v\n", err)return}fmt.Printf("%s\n", bs)
}

获取当前go文件的路径

可以通过获取当前go文件的路径,然后用相对于当前go文件的路径去打开文件

package mainimport ("fmt""runtime"
)// GetCurrentFilePath 获取当前文件路径
func GetCurrentFilePath() string {_, file, _, _ := runtime.Caller(1)return file
}func main() {path := GetCurrentFilePath()fmt.Println(path)
}

分片读

package mainimport ("fmt""io""os"
)func main() {file, err := os.Open("./test.txt")if err != nil {panic(err)}defer file.Close()for {buf := make([]byte, 32)_, err = file.Read(buf)if err == io.EOF {break}if err != nil {panic(err)}fmt.Printf("%s", buf)}
}

按缓冲读

按行读
package mainimport ("bufio""fmt""os"
)func main() {file, err := os.Open("./test.txt")if err != nil {fmt.Printf("Open file error: %v\n", err)return}defer file.Close()reader := bufio.NewReader(file)for {// 按行读取line, _, err := reader.ReadLine()fmt.Println(string(line))if err != nil {break}}
}
光标操作
package mainimport ("bufio""fmt""io""os"
)func main() {file, err := os.Open("./test.txt")if err != nil {fmt.Printf("Open file error: %v\n", err)return}defer file.Close()// 开始位置前进5个字节var whence = 0var offset int64 = 5pos, _ := file.Seek(offset, whence)fmt.Println("Jump forward 5 bytes from start position:", pos)// 当前位置回退2个字节whence = 1offset = -2pos, _ = file.Seek(offset, whence)fmt.Println("Jump back 2 bytes from current position:", pos)reader := bufio.NewReader(file)for {// 按行读取line, err := reader.ReadString('\n')if err == io.EOF {break}fmt.Print(line)}
}
按分割符读
package mainimport ("bufio""fmt""os"
)func main() {file, err := os.Open("./test.txt")if err != nil {fmt.Printf("Open file error: %v\n", err)return}defer file.Close()scanner := bufio.NewScanner(file)scanner.Split(bufio.ScanWords) // 按照单词读//scanner.Split(bufio.ScanLines) // 按照行读//scanner.Split(bufio.ScanRunes) // 按照中文字符读//scanner.Split(bufio.ScanBytes) // 按照字节读读,中文会乱码for scanner.Scan() {fmt.Println(scanner.Text())}err1 := scanner.Err()if err1 != nil {panic(err1)}
}

2.文件写入

文件的打开方式

os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)
os.Create(name string) (*File, error)
io/ioutil.Write(filename string, data []byte, perm fs.FileMode) error文件操作模式:
覆盖写:os.O_WRONLY | os.O_TRUNC
追加写:os.O_WRONLY | os.O_APPEND
读写并追加:os.O_RDWR | os.OS_APPEND

完整的

const (O_RDONLY int = syscall.O_RDONLY // 只读O_WRONLY int = syscall.O_WRONLY // 只写O_RDWR   int = syscall.O_RDWR   // 读写O_APPEND int = syscall.O_APPEND // 追加O_CREATE int = syscall.O_CREAT  // 如果不存在就创建O_EXCL   int = syscall.O_EXCL   // 文件必须不存在O_SYNC   int = syscall.O_SYNC   // 同步打开O_TRUNC  int = syscall.O_TRUNC  // 打开时清空文件
)

文件的权限

主要用于linux系统,在windows下这个参数会被无视,代表文件的模式和权限位,

三个占位符

第一个是文件所有者所拥有的权限

第二个是文件所在组对其拥有的权限

第三个占位符是指其他人对文件拥有的权限

根据UNIX系统的权限模型,文件或目录的权限模式由三个数字表示,分别代表 所有者(Owner) 、组(Group) 和 其他用户(Other) 的权限。每个数字由三个比特位组成,分别代表读、写和执行权限。因此,对于一个mode参数值,它的每一个数字都是一个八进制数字,代表三个比特位的权限组合

R:读,Read的缩写,八进制值为 4;
W:写,Write的缩写,八进制值为 2;
X:执行,Execute的缩写,八进制值为 1;

0444 表示三者均为只读的权限;
0666 表示三者均为“读写”的权限;
0777 表示三者均为读写执行的权限;
0764 表示所有者有读写执行(7=4+2+1)的权限,组有读写(6=4+2)的权限,其他用户则为只读(4=4); 

常规写

package mainimport ("fmt""os"
)func main() {file, err := os.OpenFile("./test1.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)if err != nil {panic(err)}defer file.Close()byteSlice := []byte("hello world!")bytesWritten, err := file.Write(byteSlice)if err != nil {panic(err)}fmt.Printf("Wrote %d bytes\n", bytesWritten)
}

快速写

package mainimport "io/ioutil"func main() {err := ioutil.WriteFile("abc.txt", []byte("add a new line"), 0644)if err != nil {panic(err)}
}

缓冲写

package mainimport ("bufio""os"
)func main() {file, err := os.OpenFile("./test1.txt", os.O_CREATE|os.O_WRONLY, 0600)if err != nil {panic(err)}defer file.Close()msg := "Hello World!\n"writer := bufio.NewWriter(file)for i := 0; i < 5; i++ {writer.Write([]byte(msg))}writer.Flush()
}

3.文件复制

将src文件的内容复制到dst文件

package mainimport ("fmt""io""os"
)func main() {read, _ := os.Open("./file1.txt")write, _ := os.Create("./file3.txt") // 默认是 可读可写,不存在就创建,清空文件n, err := io.Copy(write, read)fmt.Println(n, err)
}

4.目录操作

package mainimport ("fmt""os"
)func main() {dir, _ := os.ReadDir("../go_study")for _, entry := range dir {info, _ := entry.Info()fmt.Println(entry.Name(), info.Size()) // 文件名,文件大小,单位比特}
}

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

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

相关文章

C++:异常处理

异常处理中对象参数与引用参数的选择 User&#xff1a; catch()中的参数如果使用基类的引用&#xff0c;是不是相当于声明了一个引用&#xff0c;它是基类类型的&#xff0c;catch 到 throw的抛出的对象之后&#xff0c;就相当于这个基类引用指向了抛出的对象&#xff1f; C…

解决FLINK CDC监控oracle报Failed to parse insert DML问题

更多优秀文章,请扫码关注个人微信公众号或搜索“程序猿小杨”添加。 一、错误展现: Caused by: io.debezium.connector.oracle.logminer.parser.DmlParserException: Failed to parse insert DML: insert into "HIS_DATA". at io.debezium.connector.oracle.logm…

Nginx内存池相关源码剖析(三)小块内存分配逻辑

在Nginx中&#xff0c;小块内存通常指的是那些大小相对较小、分配和释放频率较高的内存块。这些内存块由于数量众多、管理复杂&#xff0c;因此需要使用一种高效的内存管理机制来减少内存管理的开销和内存碎片的产生。 Nginx内存池通过一种预分配和复用的方式来管理小块内存。当…

觉飞、希亦、Daily neaty内衣洗衣机好用吗?爆款产品性能全面测评!

近几年来小家电产品中&#xff0c;内衣洗衣机的讨论热度无疑是最大的&#xff0c;功能多、操作方便&#xff0c;用内衣洗衣机来清洗内衣裤会更加卫生和安全&#xff0c;能满足了消费者的多种需求。不过尽管市面上的内衣洗衣机品牌很多、挑选空间大&#xff0c;也不是所有产品都…

RT-thread-线程间通讯3-事件集

事件集 事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。 一个线程和多个事件的关系可设置为: 其中任意一个事件唤醒 线程,或几个事件都到达后唤醒线程,多个事件集合可以用一个32bit无符号整型变量来表示,…

4.8-4.12算法刷题笔记

刷题 堆1. 堆排序2. 模拟堆 哈希表3. 模拟散列表4. 字符串哈希 DFS5. 排列数字6. n-皇后问题 2. BFS&#xff08;队列&#xff09;7. 字母迷宫8. 滑动谜题 3. 树与图的dfs9. 树的重心 4. 树与图的bfs(最短路)10. 图中点的层次( 无权最短路 ) 5. 拓扑排序11. 课程表 6. 朴素dijk…

人工智能时代的图像识别:机遇与挑战并存

人工智能&#xff08;AI&#xff09;时代为图像识别领域带来了前所未有的机遇&#xff0c;同时也伴随着一系列挑战。这一领域的发展不仅深刻影响了科技、医疗、教育、娱乐等多个行业&#xff0c;还在一定程度上改变了人们的生活方式。 机遇&#xff1a; 技术突破与创新&#…

prometheus.yaml

目录 一、说明1、全局配置 global&#xff1a;2、告警配置 alerting&#xff1a;3、规则文件配置 rule_files&#xff1a;4、拉取配置 scrape_configs&#xff1a;5、远程读写配置 remote_read/remote_write&#xff1a; 二、简单配置示例&#xff1a; 一、说明 prometheus的配…

GoLang核心知识点

目录 1. 系统中断信号注册 2. 通道接收多个返回值 3. go context 4. reflect 5. json字符串对象转换 1. 系统中断信号注册 interrupt : make(chan os.Signal) // 可以控制强制终止的信号 // 如果系统有中断信号&#xff0c;发送给r.interrupt signal.Notify(interrupt, os…

docker (CentOS,ubuntu)安装及常用命令

Docker和虚拟机一样&#xff0c;都拥有环境隔离的能力&#xff0c;但它比虚拟机更加轻量级&#xff0c;可以使资源更大化地得到应用 Client&#xff08;Docker客户端&#xff09;&#xff1a;是Docker的用户界面&#xff0c;可以接受用户命令&#xff08;docker build&#xff…

纯前端umi项目部署页面自动刷新

背景 在用户正在访问单页面网站的情况下&#xff0c;突然发布了新的版本。而由于单页面中路由特性&#xff0c;或浏览器缓存的原因&#xff0c;并不会随着路由变化而重新加载前端资源&#xff0c;此时用户浏览器所运行的脚本&#xff0c;并非是最新的代码&#xff0c;从而可能…

img标签图片未加载完成占位图

通过Css控制&#xff0c;实现加载接口下发或者网络图片时&#xff0c;未加载完成前&#xff0c;先加载本地一张占位图&#xff0c;记载完成显示接口下发的图或者网络图。 实现方式&#xff1a;通过在img标签的after伪元素上添加一张占位图&#xff0c;并且img标签都设置为posi…

记录Python的pandas库详解

如何生成一个pd import pandas as pd df pd.DataFrame([[1,2,3],[4,5,6]],index[A,B],columns[C1,C2,C3])df ---------------------------------------------------------------------------C1 C2 C3 A 1 2 3 B 4 5 6df.T -------------------------------------------------…

爬虫 新闻网站 以湖南法治报为例(含详细注释) V4.0 升级 自定义可任意个关键词查询、时间段、粗略判断新闻是否和优化营商环境相关,避免自己再一个个判断

目标网站&#xff1a;湖南法治报 爬取目的&#xff1a;为了获取某一地区更全面的在湖南法治报的已发布的和优化营商环境相关的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&a…

element-ui container 组件源码分享

今日简单分享 container 组件的源码实现&#xff0c;从以下两个方面来讲解&#xff1a; 1、container 组件的页面结构 2、container 组件的属性 一、container 组件的页面结构 二、container 组件的属性 1、container 部分的 direction 属性&#xff0c;子元素的排列方向&am…

Nacos2.3.0安装部署

一&#xff0c;准备安装包 github下载点 二&#xff0c;在/usr/local/目录下创建一个文件夹用于上传和解压Nacos cd /usr/local/ #上传Nacos文件 #解压之前cd进安装包根目录 cd /usr/local/ #这边选择的Nacos版本为2.3.0 tar -zxxvf nacos-server-2.3.0.tar.gz #把该文件移动…

Spring Boot安装与配置

一、引言 Spring Boot是一个开源的Java框架&#xff0c;用于简化Spring应用的创建、运行和部署过程。它遵循“约定优于配置”的原则&#xff0c;使得开发者能够更专注于业务逻辑的实现&#xff0c;而非繁琐的配置。本教程将指导您完成Spring Boot的安装和配置过程&#xff0c;…

基于SpringBoot的“商务安全邮箱”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“商务安全邮箱”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构 收件箱效果图 草稿箱效果图 已发送…

【数据结构】习题之消失的数字和轮转数组

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《数据结构》 &#x1f389;前路漫漫亦灿灿 前言 消失的数字这道题目我会和大家分享三种思路。 还有一道题目是轮转数组&#xff0c;&#xff0c;也会分享三种思路&#xff0c;大…

常见的垃圾回收器(下)

文章目录 G1ShenandoahZGC 常见垃圾回收期&#xff08;上&#xff09; G1 参数1&#xff1a; -XX:UseG1GC 打开G1的开关&#xff0c;JDK9之后默认不需要打开 参数2&#xff1a;-XX:MaxGCPauseMillis毫秒值 最大暂停的时间 回收年代和算法 ● 年轻代老年代 ● 复制算法 优点…