Go異常處理、泛型和文件操作實(shí)例代碼
一:異常處理
go的異常處理可能是這門語(yǔ)言唯一的一個(gè)詬病了吧
由于 go 語(yǔ)言沒有捕獲異常的機(jī)制,導(dǎo)致每調(diào)一個(gè)函數(shù)都要接一下這個(gè)函數(shù)的 error
網(wǎng)上有個(gè)梗,叫做 error 是 go 的一等公民
常見的異常處理
向上拋
將錯(cuò)誤交給上一級(jí)處理
一般是用于框架層,有些錯(cuò)誤框架層面不能擅做決定,將錯(cuò)誤向上拋不失為一個(gè)好的辦法
package main
import (
"errors"
"fmt"
)
func Parent() error {
err := method() // 遇到錯(cuò)誤向上拋
return err
}
func method() error {
return errors.New("出錯(cuò)了")
}
func main() {
fmt.Println(Parent())
}
中斷程序
遇到錯(cuò)誤直接停止程序
這種一般是用于初始化,一旦初始化出現(xiàn)錯(cuò)誤,程序繼續(xù)走下去也意義不大了,還不如中斷掉
package main
import (
"fmt"
"os"
)
func init() {
// 讀取配置文件中,結(jié)果路徑錯(cuò)了
_, err := os.ReadFile("xxx")
if err != nil {
panic(err.Error())
}
}
func main() {
fmt.Println("啦啦啦")
}
恢復(fù)程序
我們可以在一個(gè)函數(shù)里面,使用一個(gè) defer,可以實(shí)現(xiàn)對(duì) panic 的捕獲
以至于出現(xiàn)錯(cuò)誤不至于讓程序直接崩潰
這種一般也是框架層的異常處理所做的
package main
import (
"fmt"
"runtime/debug"
)
func read() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err) // 捕獲異常,打印錯(cuò)誤信息
// 打印錯(cuò)誤的堆棧信息
s := string(debug.Stack())
fmt.Println(s)
}
}()
var list = []int{2, 3}
fmt.Println(list[2]) // 肯定會(huì)有一個(gè)panic
}
func main() {
read()
}
當(dāng)然,這個(gè)用于捕獲異常的 defer 的延遲函數(shù)可以在調(diào)用鏈路上的任何一個(gè)函數(shù)上,但是 main中 捕獲了會(huì)直接結(jié)束程序
- panic 會(huì)層層向上拋,當(dāng)前函數(shù)不處理,defer 放到 main 函數(shù)中也是會(huì)被處理的
- 一旦 panic 發(fā)生,即使被 recover() 捕獲,當(dāng)前調(diào)用棧的“正常流程”也會(huì)中斷
二:泛型
從 1.18 版本開始,Go 添加了對(duì)泛型的支持,即類型參數(shù)
泛型函數(shù)
如果我們要實(shí)現(xiàn)一個(gè)對(duì)int類型的求和函數(shù)
func add(a, b int) int {
return a + b
}
但是這樣寫了之后,如果參數(shù)是 float 類型,int32 類型這些,就沒辦法使用了
難道要為每個(gè)類型都寫一個(gè)這樣的函數(shù)嗎?
顯然這就不合理
這個(gè)時(shí)候,泛型就上場(chǎng)了
func add[T int | float64 | int32](a, b T) T {
return a + b
}
type Number interface {
int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64
}
func plus[T Number](n1, n2 T) T {
return n1 + n2
}
泛型結(jié)構(gòu)體
package main
import (
"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: "楓楓",
// },
//}
//byteData, _ := json.Marshal(user)
//fmt.Println(string(byteData))
//userInfo := Response{
// Code: 0,
// Msg: "成功",
// Data: UserInfo{
// Name: "楓楓",
// Age: 24,
// },
//}
//byteData, _ = json.Marshal(userInfo)
//fmt.Println(string(byteData))
var userResponse Response[User]
json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"楓楓"}}`), &userResponse)
fmt.Println(userResponse.Data.Name)
var userInfoResponse Response[UserInfo]
json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"楓楓","age":24}}`), &userInfoResponse)
fmt.Println(userInfoResponse.Data.Name, userInfoResponse.Data.Age)
}
泛型切片
package main
type MySlice[T any] []T
func main() {
var mySlice MySlice[string]
mySlice = append(mySlice, "楓楓")
var intSlice MySlice[int]
intSlice = append(intSlice, 2)
}
泛型 map
package main
import "fmt"
type MyMap[K string | int, V any] map[K]V
func main() {
var myMap = make(MyMap[string, string])
myMap["name"] = "楓楓"
fmt.Println(myMap)
}
三:文件操作
文件讀取
一次性讀取
byteData, _ := os.ReadFile("go_study/hello.txt")
fmt.Println(string(byteData))獲取當(dāng)前go文件的路徑
可以通過獲取當(dāng)前 go 文件的路徑,然后用相對(duì)于當(dāng)前 go 文件的路徑去打開文件
// GetCurrentFilePath 獲取當(dāng)前文件路徑
func GetCurrentFilePath() string {
_, file, _, _ := runtime.Caller(1)
return file
}
分片讀
file, _ := os.Open("go_study/hello.txt")
defer file.Close()
for {
buf := make([]byte, 1)
_, err := file.Read(buf)
if err == io.EOF {
break
}
fmt.Printf("%s", buf)
}
帶緩沖讀
按行讀
file, _ := os.Open("go_study/hello.txt")
buf := bufio.NewReader(file)
for {
line, _, err := buf.ReadLine()
fmt.Println(string(line))
if err != nil {
break
}
}
指定分割符
file, _ := os.Open("go_study/hello.txt")
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanWords) // 按照單詞讀
//scanner.Split(bufio.ScanLines) // 按照行讀
//scanner.Split(bufio.ScanRunes) // 按照中文字符讀
//scanner.Split(bufio.ScanBytes) // 按照字節(jié)讀讀,中文會(huì)亂碼
for scanner.Scan() {
fmt.Println(scanner.Text())
}
文件寫入
一次性寫
err := os.WriteFile("go_study/file1.txt", []byte("這是內(nèi)容"), os.ModePerm)
fmt.Println(err)
文件的打開方式
常見的一些打開模式
// 如果文件不存在就創(chuàng)建 os.O_CREATE|os.O_WRONLY // 追加寫 os.O_APPEND|os.O_WRONLY // 可讀可寫 os.O_RDWR
完整的模式
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 // 如果不存在就創(chuàng)建 O_EXCL int = syscall.O_EXCL // 文件必須不存在 O_SYNC int = syscall.O_SYNC // 同步打開 O_TRUNC int = syscall.O_TRUNC // 打開時(shí)清空文件 )
文件的權(quán)限
主要用于linux系統(tǒng),在windows下這個(gè)參數(shù)會(huì)被無(wú)視,代表文件的模式和權(quán)限位
文件復(fù)制
io.Copy(dst Writer, src Reader) (written int64, err error)
將 src 文件的內(nèi)容復(fù)制到 dst 文件
read, _ := os.Open("go_study/file1.txt")
write, _ := os.Create("go_study/file3.txt") // 默認(rèn)是 可讀可寫,不存在就創(chuàng)建,清空文件
n, err := io.Copy(write, read)
fmt.Println(n, err)
目錄操作
dir, _ := os.ReadDir("go_study")
for _, entry := range dir {
info, _ := entry.Info()
fmt.Println(entry.Name(), info.Size()) // 文件名,文件大小,單位比特
}
四:總結(jié)
到此這篇關(guān)于Go異常處理、泛型和文件操作的文章就介紹到這了,更多相關(guān)Go異常處理、泛型和文件操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語(yǔ)言計(jì)算兩個(gè)時(shí)間的時(shí)間差方法
這篇文章主要介紹了go語(yǔ)言計(jì)算兩個(gè)時(shí)間的時(shí)間差方法,涉及Python操作時(shí)間的技巧,需要的朋友可以參考下2015-03-03
GoLang調(diào)用鏈可視化go-callvis使用介紹
與鏈路追蹤(Tracing)不同,Tracing關(guān)注復(fù)雜的分布式環(huán)境中各個(gè)服務(wù)節(jié)點(diǎn)間的調(diào)用關(guān)系,主要用于服務(wù)治理。而我們本次探索的代碼調(diào)用鏈路則是代碼方法級(jí)別的調(diào)用關(guān)系,主要用于代碼設(shè)計(jì)2023-02-02
Go語(yǔ)言中的匿名結(jié)構(gòu)體用法實(shí)例
這篇文章主要介紹了Go語(yǔ)言中的匿名結(jié)構(gòu)體用法,實(shí)例分析了匿名結(jié)構(gòu)體的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
Go項(xiàng)目關(guān)閉終端后停止運(yùn)行的3種實(shí)用解決方案
在Go項(xiàng)目部署過程中,很多開發(fā)者都會(huì)遇到一個(gè)共性問題:通過終端啟動(dòng)程序后,一旦關(guān)閉終端,程序就會(huì)隨之停止運(yùn)行,本文將介紹3種可靠方案,徹底解決這一問題,確保Go程序在服務(wù)器上穩(wěn)定運(yùn)行,需要的朋友可以參考下2025-08-08
go語(yǔ)言beego框架jwt身份認(rèn)證實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go語(yǔ)言beego框架jwt身份認(rèn)證實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
使用Golang實(shí)現(xiàn)Sm2加解密的代碼詳解
本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)Sm2加解密的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03

