Go语言学习| 青训营

60 阅读2分钟

学习目标

  • 记录自己的学习
  • 重温自己的学习成果

defer

  • 包含该defer语句的函数执行完毕时,defer后的函数才会被执行

  • 四字:推迟调用

    • 在一个函数中执行多条defer语句,它们的执行顺序和声明顺序相反(栈的缘故)

    • 原理

      • 推迟的函数调用会被压入一个中。
      • 当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
    • defer、return、返回值的执行顺序

      • return最先给返回值赋值
      • defer开始执行一些收尾工作
        • 若为有名返回值a()(i int)则直接赋值,defer可以访问这个返回值
        • 若为匿名返回值b()int则先声明再赋值,defer访问的值来自于其他变量的赋值,修改的也是其他变量的值,defer无法直接访问到我们需要的返回值
      • RET指令(返回指令前先检查是否存在defer语句)携带返回值退出函数
    • 注意:

      • defer声明时会先计算确定参数的值,defer推迟执行的仅是其函数体。
      • 如time.Now(),虽然defer,但是实际上time.Now已经存起来了
      • 作用域
        • defer 只对当前协程有效(main 可以看作是主协程)

        • 当任意一条(主)协程发生 panic 时,会执行当前协程中 panic 之前已声明的 defer

        • 在发生 panic 的协程中,如果没有一个 defer 调用 recover()进行恢复,则会在执行完最后一个已声明(已经入栈)的 defer 后,引发整个进程崩溃

        • 主动调用 os.Exit(int) 退出进程时,defer 将不再被执行。

  • 匿名函数:func(){语句}() 最后的括号很重要

结构体转map

  1. json包的marshal,unmarshal

    • 先将结构体序列化成[]byte数组,再从[]byte数组序列化成结构体。
    •   data, _ := json.Marshal(&user)
        m := make(map[string]interface{})
        json.Unmarshal(data, &m)
      
    • 简单但是效率低
  2. 反射

    • 使用反射将结构体转成map的方法。通过标签(tag)和反射
      1. 标签识别

        • 使用readTag方法读取域(field)的标签,如果没有标签,使用域的名字。然后读取tag中的选项。目前支持3个选项
          • '-':忽略当前这个域
          • 'omitempty' : 当这个域的值为空,忽略这个域
          • 'dive' : 递归地遍历这个结构体,将所有字段作为键
          • 通过传入结构体反射,读tag,然后去遍历
      2. 结构体的域(field)的遍历

        • 遍历结构体的每一个与,然后通过swithc存值
      3. 内嵌结构体的转换

        • 如果时检查有没有传入参数的方法,实现了调用这个方法
        • 没有实现,递归调用StructToMap,根据是否展开(dive)把结果写入map中