golang learning 2

数据类型

int/uint类型位数不是固定的,根据运行平台可能是32位或64位 获取Int类型位数:strconv.IntSize

Go不允许隐式类型转换,只能强制转换 强制转换:int32(a)

float32/float64,分别精确到小数点后7/15位

byte别名uint8

string是指类型,默认值是空字符串,而不是nil

指针

Go不支持指针运算,指针保存了值的内存地址。

& 操作符会生成一个指向其操作数的指针,* 操作符表示指针指向的底层值

go语言只有值传递,没有引用传递(方法参数为指针时,同样是值传递,因为传递的是指针地址) 函数调用时,传变量,是copy了一份变量,传到函数使用,函数内修改不影响原变量值;传指针时,是copy了一份指针,而不是引用传递。

当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。 传指针比较较量级(8bytes),只是传内存地址,我们可以用指针传递体积较大的结构体。如果用参数值传递的话,在每次copy上就会花费相对较多的系统开销(内存和时间)。所以当要传递大的结构体时,用指针是一个明智的选择。

指针变量指向一个值的内存地址,*用于指定变量是作为一个指针;数组不用加*来操作数组,go可以自动识别

Go语言中string,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递(注:若函数需改变slice长度,仍需要取地址传递指针)

常量

Go中常量一般不用大写,因为大写表示public

常量定义但不使用,不会报错

iota是常量的计数器,从0开始,组中每定义1个常量自动递增1;每遇到一个const关键字,iota就会重置为0

运算符

++和–,在go语言中是语句而不是表达式,所以不能放在等号右边,只能做为单独一行

位移

<<,左移n位,即等以2的n次方 >>,右移n位,即除以2的n次方

PS:1 « 10 = 1024,即1K;1 « 20 = 1048576,即1M

条件语句

switch语句,case后面不用加break 默认case匹配成功后,不地执行其他case,如果需要执行后面case,可以使用fallthrough,此时会进行下一项case,且不做条件判断!!!

函数

在一个结构体内,最好统一接收者为指针实例,因为:

  1. 指针实例可以调用接受者是指针的函数和接受者为实例的函数;普通实例(非指针实例)只能调用接受者实例的函数,而不能调用接受者是指针的函数
  2. 以interface做为类型判定的时候,结构体内实现interface的函数同时存在指针实例和普通实例的情况下,不能被正确识别类型

数组和切片

切片是数组的连续片断引用

初始化[]表示切片类型,不需要指定大小 也可以用make初始化,make([]T, length, capacity),len为切片的实际长度,capacity为切片第1个元素在底层数组的位置,到底层数组结尾位置的长度

切片自动扩容规则:容量小于1024,则每次*2;大于等于1024,每次增加1/4 此时数组会还原,切片指向分配的新数组,与原数组无关联

数组初始化,可以用:[3]{0:1, 1:3, 2:4}的方式,相当于{1,3,4}

slice是引用类型,底层是数组。一般用make创建(new返回的是指针,则实际是指向指针的指针,基本没意义) 数组是值类型,不是引用类型。被当成方法参数时,传递的是值的copy,不是地址

参数为…形式的是值传递,区别于传slice参数的地址传递

fmt

fmt占位符:https://golang.org/pkg/fmt/#hdr-Printing

类型断言

语法:value, ok := em.(T)

  • em代表要判断的变量,必须是interface类型
  • T代表被判断的类型,如果是em指针类型,则T需要改为*T
  • value代表返回的值
  • ok代表是否为改类型

或者不传入具体类型,用type替代,让系统判断,如:value, ok := em.(type)

经常与switch一起组合使用

defer

defer在方法调用结束后,return调用前执行 多个defer同时存在时,是以栈的形式,先进后出,FILO 多用于释放资源(个人理解应该是确保释放资源,因为资源不用应该及时释放,而不是依赖于defer,defer的存在只是为了确保方法完成后资源会释放)

defer定义的操作,在发生error和panic时仍然会被执行,调用panic之后定义的defer不会运行,因为未入栈

os.Exit调用后,defer不会运行

错误处理

结构体实现了Error()时,对于返回error的,可以直接返回结构体。因为ducker typing

结构体

go语言中的方法是作用在特定类型的变量上,因此自定义的类型都可以有方法,不仅仅是在结构体中

WaitGroup

不用初始化就能使用,但是!如果要当参数传递,必须是指针!!!这里采过坑!因为Go只有值传递,所以必须传指针,指向同一个实例;否则会视为两个不同实例

map

删除map键值对,使用delete函数 map可用sort排序

包变量和结构体类型的区别

包变量类型于静态变量,不属于任何实例;结构体成员相当于类的成员变量

new/make/struct{}的区别

make 和 struct{} 一样,返回的都是值; new 返回的是指针,make返回初始化后的(非零)值 make 只能用于 map、slice、channel 的创建值引用, struct 只能用 struct{} 来创建值引用

关于文件夹名和包名

require -> mod name

import -> [mod name / ] package

关于交叉编译

1
2
# 查询go支持的系统和平台
go tool dist list

init方法的坑

只要有某个程序文件(*.go)显式引用了某个带init()方法的包,那么即使该程序文件并没有被整个程序任何地方使用过(比如结构体初始化),那么也会触发被引用包的init()方法。 举例来说:公共包common在database/redis的package下有一个redis.go文件中有init()方法,引用common包的程序a,有一个程序文件b.go,在b.go中import 了common包的database/redis,那么即使该程序文件b.go在程序a中并没有被使用过,common包的database/redis的init方法仍然会执行。很奇怪!