Golang学习中遇到的问题

不断踩坑,持续更新。



这里包含两个部分

  1. 亲身经历:自己遇到的问题,包括踩的坑,模糊的知识点,不能瞬间想到的问题等等。
  2. 他人经验:看他人的博文发现的问题,会收在第二部分中,如果有一天想通了会放到第一部分。


亲身经历:

  • 切片初始化 slice := make([]type, len)          用make创造切记len参数不能省略
  • 切片append添加的是单个元素不是切片        s = append(s[:i], s[i+1:]...)    切记...
  • append生成新切片,原切片不动(超过原切片cap时)
  • 声明多数据类型时,如果遇到换行,结尾必须是逗号或者大括号
  • 接口查询: 在一个接口变量中判断,把值赋给接口变量的对象,究竟有没有实现另一个接口。 f1,ok := f2.(f1type)
  • goroutine创建的顺序不代表是执行的顺序,会分到不同的core上执行。理论上是放于一个任务队列但是最后那个可能会放在专一的next位置。
  • 无缓冲channel默认缓冲为0
  • select 机制:
  •       select+case用于阻塞监听goroutine
  •       select底下有多个可执行的case,则随机执行一个
  •       select常配合for循环来监听channel有没有故事发生,其中break只是退出当前select
  • for range中如果使用闭包处理循环数据的话,会导致所有闭包绑定在range的最后一个元素上,最后只输出最后一个元素,可能for执行完之后goroutine才开始执行。
  • defer机制:
  •       defer先进后出的方式执行
  •       defer在for循环中可能导致性能问题
  •       defer一定要在判断err之后
  •       调用os.Exit后defer不会被执行
  •       panic遇到defer后先执行defer再传递panic
  • for range语句是对元素的拷贝后执行一系列动作,不是引用,无法改变原有元素信息
  • 注意nil map和nil slice 通过var声明没有字面量的map和slice后不会创建底层数组,无法直接添加元素
  • 误用:=可能导致变量覆盖,在内部空间中对外空间的变量使用:=重新赋值会产生新的局部变量,屏蔽外部变量,脱离内部作用域失效
  • array和struct是值类型的,而slice、map、chan、interface是引用类型,一般使用slice而不是array,struct也尽量使用指针,能够避免资源消耗和无法修改数据问题,特别注意对struct的for range行为
  • interface{}类型的变量无法调用属性,只能调用方法
  • struct属性如果是小写开头,则其序列化会丢失属性对应的值,同时也无法进行Json解析
  • 重写String()方法可能因为fmt选项原因 如%v 导致循环调用String()造成栈溢出
  • atomic.CompareAndSwapInt32(addr *int32,  oldnum, newnum int32)
  • 不能修改字典中value为结构体的属性值
  • go中的map是由哈希表实现,必须能够比较是否相等,每次遍历的顺序可以不一样。
  • 除了slice、map、function的内建类型都可以作为key,struct不包含上述类型也可以作为key
  • 将格式好的字符串输出
  •       Printf() 是把格式字符串输出到标准输出
  •       Sprintf() 是把格式字符串输出到指定字符串中,参数多一个char*,为目标字符串地址
  •       Fprintf() 是把格式字符串输出到制定文件设备中,参数多一个FILE*
  • 关键字go并非执行并发任务,而是创建一个并发任务单元
  • go语言中没有隐藏的this指针,因为方法施加的对象显式传递,没有被隐藏起来
  • go语言触发异常的场景: 空指针解析、下标越界、除数为0、调用panic函数
  • make初始化是有默认值的 如s:=make([]int,3) s = append(s,1,2,3) 得到的是[0,0,0,1,2,3]
  • 注意interface内部结构,带有方法集的接口比空接口多了一层itab结构,存储_type信息和[]fun方法集,并不代表interface是nil。
  • type只能用在interface
  • 在函数有多个返回值时,只要有一个返回值有指定命名,其他的也必须有命名
  • struct中有map、slice属性时不能直接==比较
  • 常量通常会被编译器在预处理阶段直接展开,作为指令数据使用,不能取地址
  • goto不能跳转到其他函数或者内层代码
  • type Myint1 int 和 type Myint2 int 不一样,第一个是创建一个新类型,底层是int,但不能直接=int,第二个是类型别名
  • 更新字符串字符,最好用rune,防止不用文字占用字节数不同导致无法预计的结果
  •       x := "text"
  •       xRunes := []rune(x)
  •       xRunes[0] = '我'
  •       x = string(xRunes)        x = "我ext"
  • go的内建函数len()返回的是字符串的byte数
  • 从一个现有的非interface类型创建新类型时,并不会继承原有的方法
  • map类型的key必须是可以使用==比较的类型,不能是slice、map、function。原文: As mentioned earlier, map keys may be of any type that is comparable. The language spec defines this precisely, but in short, comparable types are boolean, numeric, string, pointer, channel, and interface types, and structs or arrays that contain only those types. Notably absent from the list are slices, maps, and functions; these types cannot be compared using ==, and may not be used as map keys.
  • 使用读写锁RWMutex时,如果有重入可能会导致死锁。
  • 函数传递切片,在函数中使用append后一定要把切片做一次返回,否则原切片不会改变。
  • 闭包中的外部变量不是锁死的,会随着外部变量改变。(好像指针一样)
  • 当map需要存储大量数据时,尽量不要用含有指针的结构作为键值,GC的效率会很低。

 


 

他人经验:

 

  • 将for-select封装到函数中。 作者观点:少用break,但不是说break没用。
  • 初始化结构体时使用带标签的语法。作者观点:扩充struct时可能导致无法编译。
  • 将结构体初始化拆分为多行。作者观点:易读易用。
  • 利用 iota 来使用自定义的整数枚举类型,务必要为其添加 String() 方法。作者观点:易用易扩展
  • 重度使用map操作数据,最好设置getter、setter等方法。作者观点:逻辑封装
  • Go语言速度快主要归功于对依赖的管理。
  • 在string和[]byte之间转换,会给GC造成很大压力。底层数据结构会复制。
  • 使用+来进行string连接会生成新对象,降低GC效率,用strings.Builder来构建字符串,省时并减少内存分配次数。
  • 拼接字符串与数字是,用strconv转换要比fmt.Sprintf()快很多。

 

 



记录每天解决的一点小问题,积累起来就能解决大问题。 

你可能感兴趣的:(Golang基础学习)