11. recover的執(zhí)行時機(jī)
無,recover 必須在 defer 函數(shù)中運(yùn)行。recover 捕獲的是祖父級調(diào)用時的異常,直接調(diào)用時無效。
func main() {
recover()
panic(1)
}
直接 defer 調(diào)用也是無效。
func main() {
defer recover()
panic(1)
}
defer 調(diào)用時多層嵌套依然無效。
func main() {
defer func() {
func() { recover() }()
}()
panic(1)
}
必須在 defer 函數(shù)中直接調(diào)用才有效。
func main() {
defer func() {
recover()
}()
panic(1)
}
12. 閉包錯誤引用同一個變量問題怎么處理
在每輪迭代中生成一個局部變量 i 。如果沒有 i := i 這行,將會打印同一個變量。
func main() {
for i := 0; i < 5; i++ {
i := i
defer func() {
println(i)
}()
}
}
或者是通過函數(shù)參數(shù)傳入 i 。
func main() {
for i := 0; i < 5; i++ {
defer func(i int) {
println(i)
}(i)
}
}
13. 在循環(huán)內(nèi)部執(zhí)行defer語句會發(fā)生啥
defer 在函數(shù)退出時才能執(zhí)行,在 for 執(zhí)行 defer 會導(dǎo)致資源延遲釋放。
并且會使調(diào)用棧劇增(如果循環(huán)次數(shù)多的話),比較好的方式是使用局部函數(shù)處理。
func main() {
for i := 0; i < 5; i++ {
func() {
f, err := os.Open("/path/to/file")
if err != nil {
log.Fatal(err)
}
defer f.Close()
}()
}
}
func 是一個局部函數(shù),在局部函數(shù)里面執(zhí)行 defer 將不會有問題。
14. 說出一個避免Goroutine泄露的措施
可以通過 context 包來避免內(nèi)存泄漏。
func main() {
ctx, cancel := context.WithCancel(context.Background())
ch := func(ctx context.Context) <-chan int {
ch := make(chan int)
go func() {
for i := 0; ; i++ {
select {
case <- ctx.Done():
return
case ch <- i:
}
}
} ()
return ch
}(ctx)
for v := range ch {
fmt.Println(v)
if v == 5 {
cancel()
break
}
}
}
下面的 for 循環(huán)停止取數(shù)據(jù)時,就用 cancel 函數(shù),讓另一個協(xié)程停止寫數(shù)據(jù)。如果下面 for 已停止讀取數(shù)據(jù),上面 for 循環(huán)還在寫入,就會造成內(nèi)存泄漏。
15. 如何跳出for select 循環(huán)
通常在for循環(huán)中,使用break可以跳出循環(huán),但是注意在go語言中,for select配合時,break 并不能跳出循環(huán)。
func testSelectFor2(chExit chan bool){
EXIT:
for {
select {
case v, ok := <-chExit:
if !ok {
fmt.Println("close channel 2", v)
break EXIT//goto EXIT2
}
fmt.Println("ch2 val =", v)
}
}
//EXIT2:
fmt.Println("exit testSelectFor2")
}
16. 如何在切片中查找
go中使用 sort.searchXXX 方法,在排序好的切片中查找指定的方法,但是其返回是對應(yīng)的查找元素不存在時,待插入的位置下標(biāo)(元素插入在返回下標(biāo)前)??梢酝ㄟ^封裝如下函數(shù),達(dá)到目的。
func IsExist(s []string, t string) (int, bool) {
iIndex := sort.SearchStrings(s, t)
bExist := iIndex!=len(s) && s[iIndex]==t
return iIndex, bExist
}
17. 如何初始化帶嵌套結(jié)構(gòu)的結(jié)構(gòu)體
go 的哲學(xué)是組合優(yōu)于繼承,使用 struct 嵌套即可完成組合,內(nèi)嵌的結(jié)構(gòu)體屬性就像外層結(jié)構(gòu)的屬性即可,可以直接調(diào)用。注意初始化外層結(jié)構(gòu)體時,必須指定內(nèi)嵌結(jié)構(gòu)體名稱的結(jié)構(gòu)體初始化,如下看到 s1方式報(bào)錯,s2 方式正確。
type stPeople struct {
Gender bool
Name string
}
type stStudent struct {
stPeople
Class int
}
//嘗試4 嵌套結(jié)構(gòu)的初始化表達(dá)式
//var s1 = stStudent{false, "JimWen", 3}
var s2 = stStudent{stPeople{false, "JimWen"}, 3}
fmt.Println(s2.Gender, s2.Name, s2.Class)
18. 切片和數(shù)組的區(qū)別
數(shù)組是具有固定長度,且擁有零個或者多個,相同數(shù)據(jù)類型元素的序列。數(shù)組的長度是數(shù)組類型的一部分,所以[3]int 和 [4]int 是兩種不同的數(shù)組類型。
數(shù)組需要指定大小,不指定也會根據(jù)初始化的自動推算出大小,不可改變;數(shù)組是值傳遞。
數(shù)組是內(nèi)置類型,是一組同類型數(shù)據(jù)的集合,它是值類型,通過從0開始的下標(biāo)索引訪問元素值。在初始化后長度是固定的,無法修改其長度。當(dāng)作為方法的參數(shù)傳入時將復(fù)制一份數(shù)組而不是引用同一指針。數(shù)組的長度也是其類型的一部分,通過內(nèi)置函數(shù)len(array)獲取其長度。
數(shù)組定義:
var array [10]int
var array =[5]int{1,2,3,4,5}
切片表示一個擁有相同類型元素的可變長度的序列。切片是一種輕量級的數(shù)據(jù)結(jié)構(gòu),它有三個屬性:指針、長度和容量。
切片不需要指定大小;切片是地址傳遞;切片可以通過數(shù)組來初始化,也可以通過內(nèi)置函數(shù)make()初始化 。初始化時len=cap,在追加元素時如果容量cap不足時將按len的2倍擴(kuò)容。
切片定義:
var slice []type = make([]type, len)
19. new和make的區(qū)別
new 的作用是初始化一個指向類型的指針 (*T) 。
new 函數(shù)是內(nèi)建函數(shù),函數(shù)定義:func new(Type) Type。
使用 new 函數(shù)來分配空間。傳遞給 new 函數(shù)的是一個類型,不是一個值。返回值是指向這個新分配的零值的指針。
make 的作用是為 slice,map 或 chan 初始化并返回引用 (T)。
make 函數(shù)是內(nèi)建函數(shù),函數(shù)定義:func make(Type, size IntegerType) Type;第一個參數(shù)是一個類型,第二個參數(shù)是長度;返回值是一個類型。
make(T, args) 函數(shù)的目的與 new(T) 不同。它僅僅用于創(chuàng)建 Slice, Map 和 Channel,并且返回類型是 T(不是T)的一個初始化的(不是零值)的實(shí)例。文章來源:http://www.zghlxwxcb.cn/news/detail-821890.html
20. Printf()、Sprintf()、Fprintf()函數(shù)的區(qū)別用法是什么
都是把格式好的字符串輸出,只是輸出的目標(biāo)不一樣。文章來源地址http://www.zghlxwxcb.cn/news/detail-821890.html
- Printf(),是把格式字符串輸出到標(biāo)準(zhǔn)輸出(一般是屏幕,可以重定向)。Printf() 是和標(biāo)準(zhǔn)輸出文件 (stdout) 關(guān)聯(lián)的,F(xiàn)printf 則沒有這個限制。
- Sprintf(),是把格式字符串輸出到指定字符串中,所以參數(shù)比printf多一個char*。那就是目標(biāo)字符串地址。
- Fprintf(),是把格式字符串輸出到指定文件設(shè)備中,所以參數(shù)比 printf 多一個文件指針 FILE*。主要用于文件操作。Fprintf() 是格式化輸出到一個stream,通常是到文件。
到了這里,關(guān)于go 語言常見問題(2)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!