Golang小记

记录go语言使用中的一些注意事项。

channel

  • 通道是用来让不同goroutine之间通信的,如果只有一个goroutine,就没必要用通道

  • make(chan bool) 等价于 make(chan bool, 0) != make(chan bool, 1)

  • 默认是无缓冲通道,用于同步;有缓冲通道用于解耦

  • 不管是无缓冲通道还是有缓冲通道,只要有goroutine无限等待发生,就会死锁

  • close(channel)用来通知读该channel的goroutine退出,防止无限等待导致死锁

  • 对一个已经关闭的channel,会得到已经发送的值,等发送的值都读完后,读到通道类型对应的零值

  • 通道并不一定要关闭,除非想用来通知其他goroutine

  • 用 x := range channel 来遍历通道,当channel关闭时,循环会自动退出,不会阻塞

  • 向已经关闭的通道发送数据会导致panic;关闭已关闭的通道也会panic

  • 可以将双向通道转为单向通道。反之不行;参数传递时会隐式转换

  • select用于处理多个通道;随机选择一个到达的通道执行

  • channel可以比较,但好像也没啥意义

Timer和Ticker

  • time.NewTimer(5 * time.Second) or time.NewTicker(5 * time.Second)
  • Timer是定时器,只在指定时间后发送一个当前时间
  • Ticker为节拍器,每隔指定时间发送当前时间,不间断

数组和切片slice

​ go中很少使用数组,一般使用切片!

数组

  • 数组长度是数组类型的一部分。长度不同的数组之间无法比较
  • 两个同类型的数组可以比较。用”==”比较,比较的是数组中的元素,如果两个数组的元素都相同,则为true
  • go中数组是值传递。所以如果参数传一个很大的数组会很低效;当然也可以传递一个数组的指针
  • 声明数组时,数组中每个元素默认被初始化为零值
  • 数组指针 != 数组第一个元素的地址
  • 数组的len和cap是一样的

slice

  • slice有三个属性:指针,长度len和容量cap
  • slice的底层是数组
  • 对slice的修改就是对其底层数组的修改
  • 一个底层数组可以对应多个slice,如果多个slice都是从同一个底层数组而来,且有重叠,则修改其中一个slice,其他slice也会改变
  • slice传参是引用传递
  • slice的len为当前元素的个数;cap取决于底层数组(非循环数组),如底层数组a长度为10, s := a[3:5], 则len(s) == 2, cap(s) == 7
  • slice的零值为nil,值为nil的slice(var s []int)没有底层数组,len和cap都为0
  • 创建slice三种方式:1. 先创建数组,再从数组得到slice 2. make或字面量创建 3.从slice得到另一个slice(引用同一个底层数组)
  • 使用append对slice进行追加时,如果原有数组容量不够,会对数组扩容,每次扩为原来的两倍(不一定)
  • s := make([]int, 0) 此时slice的值为[], != nil(因为分配了底层数组,只不过数组长度为0), len和cap都为0
  • 检查slice是否为空:len(s) == 0?
  • make([]T, len, cap) 至少要有len,可以没有cap。如果不确定容量,则make([]T, 0), 等价于 s := []T{};确定容量,则make([]T, 0, cap) (适用于需要用append来填充slice的)或make([]T, cap)(适用于用下标来给slice赋值的)
  • slice append 另一个slice:x = append(x, y…)

map

  • map键的类型,必须是可以用”==”来比较的。slice不能作为键
  • 对于不存在的key,value为V类型的零值
  • map的键是唯一的,因此可以用map[T]bool来实现set,value都为true
  • 创建map两种方式:1. make(map[K]V) 2. m := map[K]V{k1:v1, k2:v2,},或者写成 var m = map[K]V{k1:v1, k2:v2,}
  • map可以用range迭代,迭代的顺序是随机的,因此如果要按序迭代,需要维护一个有序的key的slice
  • map和slice一样,都是不可比较的
  • map和slice在设置值前都必须初始化,不能只声明。var m map[K]V 只是声明了一个map,此时m为nil,没有引用任何散列表,不能赋值
  • 用make创建map的时候,不需要(也不应该)指定len,因为没有意义(底层是散列表,内存不连续,大小无限制)
  • map的容量是无限的,因此不能调用cap(m);但是可以调用len(m),结果为m中k,v对的个数
  • 无法获取map元素的地址,因为随着map的增长,已有的元素可能会被重新散列到别的位置,也就是元素的地址是不固定的
  • map的value可以是map或slice,从而实现一个key,对应多个value

反射

  • reflect.TypeOf()返回Type reflect.ValueOf()返回Value

  • Type主要用于获取类型信息,Value主要用于数据读写

  • 若要修改数据,需要传入指针,且后面必须加.Elem()获得对象实例

:=

  • 当 := 左边有两个变量,如 a, err := 时,如果之前已经声明过 err ,这里会声明新变量 a ,只会对 err 赋值,不会声明新变量 err

Copyright © 2016 - 2019 LBD's Blog All Rights Reserved.

访客数 : | 访问量 :