一法瑟、斷言
* 只要實(shí)現(xiàn)了接口的全部方法就認(rèn)為這個(gè)類型屬于接口類型,如果編寫一個(gè)接口,這個(gè)接口中沒有任何方法,這時(shí)認(rèn)為所有類型都實(shí)現(xiàn)了這個(gè)接口.所以Go語言中interface{}代表任意類型
* 如果interface{}作為方法參數(shù)就可以接收任意類型,但是在程序中有時(shí)需要知道這個(gè)參數(shù)到底是什么類型,這個(gè)時(shí)候就需要使用斷言
* 斷言使用時(shí)担巩,使用interface{}變量點(diǎn)括號(hào),括號(hào)中判斷是否屬于的類型
?? ?i interface{}
?? ?i.(Type)
* 斷言的兩大作用:
????* 判斷是否是指定類型
????* 把interface{}轉(zhuǎn)換為特定類型
* 斷言可以有一個(gè)返回值坦弟,如果判斷結(jié)果是指定類型返回變量值,如果不是指定類型則報(bào)錯(cuò)
?? ?func demo(i interface{}){
?????? ?result:=i.(int)
?????? ?fmt.Println(result)
?? ?}
?? ?func main() {
?????? ?/*
?????? ?參數(shù)是456時(shí),程序運(yùn)行正常,輸出456
?????? ?參數(shù)是false時(shí)報(bào)錯(cuò):
????????panic: interface conversion: interface {} is bool, not int
???? ?? ?*/
?????? ?demo(456)
?? ?}
* 斷言也可以有兩個(gè)返回值,這時(shí)無論是否是指定類型都不報(bào)錯(cuò).
????* 第一個(gè)參數(shù):
????????* 如果正確:返回值變量值
????????* 如果錯(cuò)誤:返回判斷類型的默認(rèn)值
????* 第二個(gè)參數(shù):
????????* 返回值為bool類型,true表示正確,false表示錯(cuò)誤
?? ?func demo(i interface{}) {
????? ??result, ok := i.(int)
????? ??fmt.Println(result, ok)
?? ?}
?? ?func main() {
?????? ?/*
?????? ?參數(shù)是456時(shí),程序運(yùn)行正常,輸出456????true
?????? ?參數(shù)是字符串"abc"時(shí)程序運(yùn)行正常,輸出0 false
???? */
?????? ?demo("abc")
?? ?}
二走诞、錯(cuò)誤
* 在程序執(zhí)行過程中出現(xiàn)的不正常情況稱為錯(cuò)誤
* Go語言中使用builtin包下的error接口作為錯(cuò)誤類型,官方源碼定義如下
????* 只包含了一個(gè)方法,方法返回值是string,表示錯(cuò)誤信息
?? ?type error interface {
?????? ?Error() string
?? ?}
* Go語言中錯(cuò)誤都作為方法/函數(shù)的返回值,因?yàn)镚o語言認(rèn)為使用其他語言類似try...catch這種方式會(huì)影響到程序結(jié)構(gòu)
* 在Go語言標(biāo)準(zhǔn)庫的errors包中提供了error接口的實(shí)現(xiàn)結(jié)構(gòu)體errorString,并重寫了error接口的Error()方法.額外還提供了快速創(chuàng)建錯(cuò)誤的函數(shù)
* 如果錯(cuò)誤信息由很多變量(小塊)組成,可以借助fmt.Errorf("verb",...)完成錯(cuò)誤信息格式化,因?yàn)榈讓舆€是errors.New()
三势决、自定義錯(cuò)誤
* 使用Go語言標(biāo)準(zhǔn)庫創(chuàng)建錯(cuò)誤,并返回
?? ?func demo(i, k int) (d int, e error) {
?????? ?if k == 0 {
????????? ??e = errors.New("初始不能為0")
?????????? ?d=0
?????????? ?return
????? ??}
?????? ?d = i / k
?????? ?return
?? ?}
?? ?func main() {
????? ??result,error:=demo(6,0)
?????? ?fmt.Println(result,error)
?? ?}
* 如果錯(cuò)誤信息由多個(gè)內(nèi)容組成,可以使用下面實(shí)現(xiàn)方式
?? ?func demo(i, k int) (d int, e error) {
?????? ?if k == 0 {
?????????? ?e = fmt.Errorf("%s%d和%d", "除數(shù)不能是0,兩個(gè)參數(shù)分別是:", i, k)
?????????? ?d = 0
?????????? ?return
????? ??}
?????? ?d = i / k
?????? ?return
?? ?}
?? ?func main() {
?????? ?result, error := demo(6, 0)
?????? ?fmt.Println(result, error)
?? ?}
四熔恢、Go語言中錯(cuò)誤處理方式
* 可以忽略錯(cuò)誤信息,使用占位符
?? ?result, _ := demo(6, 0)
* 使用if處理錯(cuò)誤,原則上每個(gè)錯(cuò)誤都應(yīng)該解決
func main() {
????result, error := demo(6, 0)
????if error != nil {
????????fmt.Println("發(fā)生錯(cuò)誤", error)
????????return
????}
????fmt.Println("程序執(zhí)行成功,結(jié)果為:", result)
}
五轻姿、defer使用
* Go語言中defer可以完成延遲功能,當(dāng)前函數(shù)執(zhí)行完成后執(zhí)行defer功能
* defer最常用的就是關(guān)閉連接(數(shù)據(jù)庫連接,文件等)可以打開連接后代碼緊跟defer進(jìn)行關(guān)閉,后面在執(zhí)行其他功能
????* 在很多語言中要求必須按照順序執(zhí)行,也就是必須把關(guān)閉代碼寫在最后,但是經(jīng)常會(huì)忘記關(guān)閉導(dǎo)致內(nèi)存溢出,而Golang中的defer很好的解決了這個(gè)問題.無論defer寫到哪里都是最后執(zhí)行
func main() {
???fmt.Println("打開連接")
???defer func(){
??????fmt.Println("關(guān)閉連接")
???}()
???fmt.Println("進(jìn)行操作")
???//輸出:打開連接 進(jìn)行操作 關(guān)閉連接
}
* 多重defer采用棧結(jié)構(gòu)執(zhí)行,先產(chǎn)生后執(zhí)行
* 在很多代碼結(jié)構(gòu)中都可能出現(xiàn)產(chǎn)生多個(gè)對(duì)象,而程序希望這些對(duì)象倒序關(guān)閉,多個(gè)defer正好可以解決這個(gè)問題
func main() {
???fmt.Println("打開連接A")
???defer func(){
??????fmt.Println("關(guān)閉連接A")
???}()
???fmt.Println("打開連接B")
???defer func(){
??????fmt.Println("關(guān)閉連接B")
???}()
???fmt.Println("進(jìn)行操作")
???//輸出:打開連接A 打開連接B 進(jìn)行操作 關(guān)閉連接B 關(guān)閉連接A
}
* defer與return同時(shí)存在時(shí),要把return理解成兩條執(zhí)行結(jié)合(不是原子指令),一個(gè)指令是給返回值賦值,另一個(gè)指令返回跳出函數(shù)
* defer和return時(shí)整體執(zhí)行順序
????* 先給返回值賦值
????* 執(zhí)行defer
????* 返回跳出函數(shù)
* 沒有定義返回值接收變量,執(zhí)行defer時(shí)返回值已經(jīng)賦值
func f() int{
????i:=0
????defer func(){
????????i=i+2
????}()
????return i
}
func main() {
????fmt.Println(f())//輸出:0
}
* 聲明接收返回值變量,執(zhí)行defer時(shí)修改了返回值內(nèi)容.
????* 由于return后面沒有內(nèi)容,就無法給返回值賦值,所以執(zhí)行defer時(shí)返回值才有內(nèi)容
func f() (i int){
????defer func(){
????????i=i+2
????}()
????return
}
func main() {
????fmt.Println(f())//輸出:2
}
六筑累、panic
* panic是builtin中函數(shù)
* panic有點(diǎn)類似于其他編程語言的throw,拋出異常.當(dāng)執(zhí)行到panic后終止剩余代碼執(zhí)行.并打印錯(cuò)誤棧信息
* 注意panic不是立即停止程序(os.Exit(0)),defer還是執(zhí)行的.
七袱蜡、recover
* recover()表示恢復(fù)程序的panic(),讓程序正常運(yùn)行
* recover()是和panic(v)一樣都是builtin中函數(shù),可以接收panic的信息,恢復(fù)程序的正常運(yùn)行
* recover()一般用在defer內(nèi)部,如果沒有panic信息返回nil,如果有panic,recover會(huì)把panic狀態(tài)取消
* recover()只能恢復(fù)當(dāng)前函數(shù)級(jí)或當(dāng)前函數(shù)調(diào)用函數(shù)中的panic(),恢復(fù)后調(diào)用當(dāng)前級(jí)別函數(shù)結(jié)束,但是調(diào)用此函數(shù)的函數(shù)可以繼續(xù)執(zhí)行.
* panic會(huì)一直向上傳遞,如果沒有recover()則表示終止程序,但是碰見了recover(),recover()所在級(jí)別函數(shù)表示沒有panic,panic就不會(huì)向上傳遞
八、os包結(jié)構(gòu)介紹
* Go語言標(biāo)準(zhǔn)庫中os包提供了不依賴平臺(tái)的操作系統(tǒng)接口
* 設(shè)計(jì)為Unix風(fēng)格的疼阔,而錯(cuò)誤處理是go風(fēng)格的,失敗的調(diào)用會(huì)返回錯(cuò)誤值而非錯(cuò)誤碼戒劫。通常錯(cuò)誤值里包含更多信息
* os包及子包功能
?? ?-- os 包
??? ??--os/exec 包,負(fù)責(zé)執(zhí)行外部命令.
???? ?--os/signal對(duì)輸入信息的訪問
???? ?--os/user 通過名稱或ID????查詢用戶賬戶
* 在os/user中提供了User結(jié)構(gòu)體,表示操作系統(tǒng)用戶
????* Uid 用戶id
????* Gid 所屬組id
????* Username 用戶名
????* Name 所屬組名
????* HomeDir 用戶對(duì)應(yīng)文件夾路徑
* 在os/user中的Group表示用戶所屬組
????* Gid 組的id
????* Name 組的名稱
* 整個(gè)os/user包中內(nèi)容比較少,提供了兩個(gè)錯(cuò)誤類型和獲取當(dāng)前用戶,查找用戶
* 可以獲取當(dāng)前用戶或查找用戶后獲取用戶信息
???// 獲取當(dāng)前登錄用戶
???// u,_:=user.Current()
? ?// Lookup()參數(shù)是用戶名,按照用戶名查找指定用戶對(duì)象
? ?// 注意:必須使用完整名稱不可以只寫zhang
???u, _ := user.Lookup(`LAPTOP-M7D47U95\zhang`)
???fmt.Println(u.Name)
???fmt.Println(u.Gid)
???fmt.Println(u.HomeDir)
???fmt.Println(u.Uid)
???fmt.Println(u.Username)