go基础语法50问,来看看你的go基础合格了吗?( 三 )


func main() {defer func() {func() { recover() }()}()panic(1)}必须在 defer 函数中直接调用才有效 。
func main() {defer func() {recover()}()panic(1)}12.闭包错误引用同一个变量问题怎么处理在每轮迭代中生成一个局部变量 i。如果没有 i := i 这行,将会打印同一个变量 。
func main() {for i := 0; i < 5; i++ {i := idefer func() {println(i)}()}}或者是通过函数参数传入 i。
func main() {for i := 0; i < 5; i++ {defer func(i int) {println(i)}(i)}}13.在循环内部执行defer语句会发生啥defer 在函数退出时才能执行,在 for 执行 defer 会导致资源延迟释放 。
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 是一个局部函数,在局部函数里面执行 defer 将不会有问题 。
14.说出一个避免Goroutine泄露的措施可以通过 context 包来避免内存泄漏 。
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():returncase ch <- i:}}} ()return ch}(ctx)for v := range ch {fmt.Println(v)if v == 5 {cancel()break}}}下面的 for 循环停止取数据时,就用 cancel 函数,让另一个协程停止写数据 。如果下面 for 已停止读取数据,上面 for 循环还在写入,就会造成内存泄漏 。
15.如何跳出for select 循环通常在for循环中,使用break可以跳出循环,但是注意在go语言中,for select配合时,break 并不能跳出循环 。
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 方法,在排序好的切片中查找指定的方法,但是其返回是对应的查找元素不存在时,待插入的位置下标(元素插入在返回下标前) 。
可以通过封装如下函数,达到目的 。
func IsExist(s []string, t string) (int, bool) {iIndex := sort.SearchStrings(s, t)bExist := iIndex!=len(s) && s[iIndex]==treturn iIndex, bExist}17.如何初始化带嵌套结构的结构体go 的哲学是组合优于继承,使用 struct 嵌套即可完成组合,内嵌的结构体属性就像外层结构的属性即可,可以直接调用 。
注意初始化外层结构体时,必须指定内嵌结构体名称的结构体初始化,如下看到 s1方式报错,s2 方式正确 。
type stPeople struct {Gender boolName string}type stStudent struct {stPeopleClass int}//尝试4 嵌套结构的初始化表达式//var s1 = stStudent{false, "JimWen", 3}var s2 = stStudent{stPeople{false, "JimWen"}, 3}fmt.Println(s2.Gender, s2.Name, s2.Class)18.切片和数组的区别数组是具有固定长度,且拥有零个或者多个,相同数据类型元素的序列 。数组的长度是数组类型的一部分,所以[3]int 和 [4]int 是两种不同的数组类型 。数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变;数组是值传递 。数组是内置类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值 。在初始化后长度是固定的,无法修改其长度 。
当作为方法的参数传入时将复制一份数组而不是引用同一指针 。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度 。数组定义:
var array [10]intvar array =[5]int{1,2,3,4,5}切片表示一个拥有相同类型元素的可变长度的序列 。切片是一种轻量级的数据结构,它有三个属性:指针、长度和容量 。切片不需要指定大小;切片是地址传递;切片可以通过数组来初始化,也可以通过内置函数make()初始化。初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容 。切片定义:

经验总结扩展阅读