首页 > 其他分享 >go基础语法10问(2)

go基础语法10问(2)

时间:2024-08-07 20:28:23浏览次数:9  
标签:10 函数 defer int 数组 语法 func go main

1.recover的执行时机

无,recover 必须在 defer 函数中运行。recover 捕获的是祖父级调用时的异常,直接调用时无效。

func main() {
    recover()
    panic(1)
}

直接 defer 调用也是无效。

func main() {
    defer recover()
    panic(1)
}

defer 调用时多层嵌套依然无效。

func main() {
    defer func() {
        func() { recover() }()
    }()
    panic(1)
}

必须在 defer 函数中直接调用才有效。

func main() {
    defer func() {
        recover()
    }()
    panic(1)
}

2.闭包错误引用同一个变量问题怎么处理

在每轮迭代中生成一个局在这里插入代码片部变量 i 。如果没有 i := i 这行,将会打印同一个变量。

func main() {
    for i := 0; i < 5; i++ {
        i := i
        defer func() {
            println(i)
        }()
    }
}

或者是通过函数参数传入 i 。

func main() {
    for i := 0; i < 5; i++ {
        defer func(i int) {
            println(i)
        }(i)
    }
}

3.在循环内部执行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()
        }()
    }
}

unc 是一个局部函数,在局部函数里面执行 defer 将不会有问题。

4.说出一个避免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():
                    return
                case ch <- i:
                }
            }
        } ()
        return ch
    }(ctx)

    for v := range ch {
        fmt.Println(v)
        if v == 5 {
            cancel()
            break
        }
    }
}


下面的 for 循环停止取数据时,就用 cancel 函数,让另一个协程停止写数据。如果下面 for 已停止读取数据,上面 for 循环还在写入,就会造成内存泄漏。

5.如何跳出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")
}

6.如何在切片中查找

go中使用 sort.searchXXX 方法,在排序好的切片中查找指定的方法,但是其返回是对应的查找元素不存在时,待插入的位置下标(元素插入在返回下标前)。

可以通过封装如下函数,达到目的。

func IsExist(s []string, t string) (int, bool) {
    iIndex := sort.SearchStrings(s, t)
    bExist := iIndex!=len(s) && s[iIndex]==t

    return iIndex, bExist
}

7.如何初始化带嵌套结构的结构体

go 的哲学是组合优于继承,使用 struct 嵌套即可完成组合,内嵌的结构体属性就像外层结构的属性即可,可以直接调用。
注意初始化外层结构体时,必须指定内嵌结构体名称的结构体初始化,如下看到 s1方式报错,s2 方式正确。

type stPeople struct {
    Gender bool
    Name string
}

type stStudent struct {
    stPeople
    Class int
}

//尝试4 嵌套结构的初始化表达式
//var s1 = stStudent{false, "JimWen", 3}
var s2 = stStudent{stPeople{false, "JimWen"}, 3}
fmt.Println(s2.Gender, s2.Name, s2.Class)

8.切片和数组的区别

数组是具有固定长度,且拥有零个或者多个,相同数据类型元素的序列。数组的长度是数组类型的一部分,所以[3]int 和 [4]int 是两种不同的数组类型。数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变;数组是值传递。数组是内置类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。
当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度。数组定义:

var array [10]int

var array =[5]int{1,2,3,4,5}

9.new和make的区别

new 的作用是初始化一个指向类型的指针 (*T) 。new 函数是内建函数,函数定义:func new(Type) Type。使用 new 函数来分配空间。传递给 new 函数的是一个类型,不是一个值。返回值是指向这个新分配的零值的指针。
make 的作用是为 slice,map 或 chan 初始化并返回引用 (T)。make 函数是内建函数,函数定义:func make(Type, size IntegerType) Type;第一个参数是一个类型,第二个参数是长度;返回值是一个类型。
make(T, args) 函数的目的与 new(T) 不同。它仅仅用于创建 Slice, Map 和 Channel,并且返回类型是 T(不是T)的一个初始化的(不是零值)的实例。

10.Printf()、Sprintf()、Fprintf()函数的区别用法是什么

都是把格式好的字符串输出,只是输出的目标不一样。
Printf(),是把格式字符串输出到标准输出(一般是屏幕,可以重定向)。Printf() 是和标准输出文件 (stdout) 关联的,Fprintf 则没有这个限制。
Sprintf(),是把格式字符串输出到指定字符串中,所以参数比printf多一个char*。那就是目标字符串地址。
Fprintf(),是把格式字符串输出到指定文件设备中,所以参数比 printf 多一个文件指针 FILE*。主要用于文件操作。Fprintf() 是格式化输出到一个stream,通常是到文件。

标签:10,函数,defer,int,数组,语法,func,go,main
From: https://blog.csdn.net/jzpfbpx/article/details/141000429

相关文章

  • go基础语法10问(1)
    1.使用值为nil的slice、map会发生啥允许对值为nil的slice添加元素,但对值为nil的map添加元素,则会造成运行时panic。//map错误示例funcmain(){varmmap[string]intm["one"]=1//error:panic:assignmenttoentryinnilmap//m:=......
  • 10HTML+CSS
    平面转换平面转换transform,作用:为元素添加动态效果,一般与过渡配合使用⚫概念:改变盒子在平面内的形态(位移、旋转、缩放、倾斜)⚫平面转换又叫2D转换。属性⚫取值◆像素单位数值◆百分比(参照盒子自身尺寸计算结果)◆正负均可⚫技巧◆translate()只写一个值,表示......
  • 瑞云渲染动画:首充1元,立得100元渲染劵!
    瑞云渲染影视动画业务上线震撼首充福利!仅需1元,您将立即获得10元的无门槛渲染券,用户只要是第一次充值,即可享受到丰厚的渲染劵,助你动画项目加速起飞。别犹豫,立即加入,开启您的创意之旅。活动时间:长期有效面向人群:瑞云渲染动画用户新用户:注册瑞云动画填【GSZI】再领10元渲染劵!活......
  • 错误 C1128 节数超过对象文件格式限制: 请使用 /bigobj 进行编译
    错误C1128表示生成的对象文件(通常是.obj文件)中包含的节数超过了链接器的限制。这通常发生在项目包含大量代码或使用了大量模板时。解决方法是在编译时使用/bigobj选项。这个选项允许对象文件包含更多的节,从而避免这个错误。在VisualStudio中,可以通过以下几种方式......
  • web页面中直接调用c++/c/go代码?【wasm】
    背景最近在做rosbag的可视化工具,网上找了个源码参考(foxglove)。成功down下来,跑起来了。于是乎,开始研究前后端代码;结果居然花了一下午没找到后端代码,不明白为什么纯web页面就可以解析rosbag(以前都是用node.js或者c++代码解析的)。过程在找了一下午之后,又回到了老办法;看netork,果然......
  • js语法
    1.作用域1.1定于作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围″变量使不能被访问1.2分类1.2.1局部作用域1.2.1.1函数作用域在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。1.2.1.2块作用域在Javascript中使用仆}包裏的代码称为代......
  • P10814 【模板】离线二维数点
    原题链接题解对于一段区间\([l,r]\)我们可以在\(r\)的位置查询一次,然后利用差分的思想跑到l-1再查一次虽然这样不行,但是可以先在\(l-1\)的位置查询一次,然后再在\(r\)的位置查询一次,然后顺序遍历,每次遍历就把对应位置上的数激活,可以用树状数组code#include<bits/stdc+......
  • vllm+go||vllm+go-zero 流式输出
    Golang后端流式输出实现以下是如何在Golang后端实现流式输出的步骤。1.后端(Golang)首先,你需要创建一个HTTP处理器来处理前端的请求,并设置响应头以支持Server-SentEvents(SSE)。import("fmt""net/http")funcstreamHandler(whttp.ResponseWriter,r......
  • Gym102788,B - Rectangles题解
    水水水~题目链接戳我分析首先根据题目条件可得式子=>\((x-2)(y-2)=n(2x+2y-4)\)化简式子可得\[\begin{align}(x-2)(y-2)=&n(2x+2y-4)\\xy-2x-2y+4=&2nx+2ny-4n\\x(y-2n-2)=&2ny-4n-4+2y\\x=&\frac{2ny-4n-4......
  • uniapp 解决andorid10以上App文件存储到手机盘目录
    file.js方法:/**@Descripttion:*@version:V1.0.0*@Author:BaiYayong*@Date:2024-08-0610:25:48*@LastEditTime:2024-08-0715:50:33*//*使用该类应开启以下权限(读取和写入)<uses-permissionandroid:name="android.permission.READ_EXTERNAL_STOR......