Go语言必知的90个知识点

1. 函数能够返回函数类型算法

func test() func(int) {
    return func(x int) {
        println("x:", x)
    }
}

2. defer定义延迟调用,不管函数是否出错都确保结束前被调用数据库

3. ok-idiom(A跌目)模式:多返回值中用一个名为ok的布尔值来标记操做是否成功数组

4. 结构中的匿名字段,结构的实例能够直接调用匿名字段的方法和属性缓存

5. 计算机中变量是一段或者多段用来存储数据的内存,类型决定变量内存的长度和存储格式,因此咱们只能修改变量值不能修改类型安全

6. 内存分配发生在运行时,编译后的机器码不使用变量名而是直接使用内存地址访问目标数据,因此编码阶段采用易于阅读的变量名闭包

7. 惯例建议以组的方式整理多行变量定义 var {x,y int }  type{ xxx }架构

8. 简短声明通常用于函数多返回值,以及if for switch等语句中定义局部变量并发

9. 未使用的局部变量会编译出错,全局变量不报错app

10. 命名建议字母或下划线开始,多字母数字和下划线组合,局部变量优先短名函数

11. 常量实在预处理阶段展开成指令数据,变量是在运行期分配存储内存.(因此常量没法寻址,没有地址)

12. byte是uint8的别名 rune是int32的别名 别名直接能够相互赋值不须要类型转换

13. 拥有相同的底层结构不表明就属于别名

14. new为指定类型分配零值内存返回指针;make是引用类型专用的建立函数(内存分配和属性初始化)

15. 未命名类型:数组、切片、字典、通道等类型与具体元素类型或长度等属性相关的类型,能够用type将其改变成命名类型

16. 对于未命名类型 struct tag不一样也属于不一样类型,字段顺序不一样也属于不一样类型。

17. 乘幂和绝对值运算在math包的Pow和Abs中

18. 自增自减只能做为独立语句

19. 指针是实体会分配内存空间,内存地址是内存中每一个字节单元的惟一编号

20. 指针类型指向相同地址或nil则相等,可是不能作加减和类型转换

21. unsafe.Pointer将指针转换为uintptr进行加减运算,但可能形成非法访问

22. 指针不能用->,统一使用.

23. 复合类型初始化,必须包含类型标签;左花括号必须在类型尾部;多成员都好隔开;多行右侧必须是逗号或者花括号

24. switch 无需显式执行break,可是想顺序执行须要显式执行fallthrough

25. range迭代是复制数据

26. goto只能跳转到同级代码,不能跨级别

27. break用于switch for select,终止整个语句块执行

28. continue只用于for循环,终止后续逻辑当即进入下一轮循环

29. 函数无需前置声明;不支持命名嵌套定义;不支持同名重载;不支持默认参数;支持不定长参数;支持多返回值;支持命名返回值;支持匿名函数和闭包

30. 函数类型只支持nil判断,不支持其余比较操做

31. 从函数返回局部变量指针是安全的,编译器会经过逃逸分析来决定是否在堆上分配内存;因此参数尽可能减小值拷贝

32. 函数建议命名规则:动词+名称;避免没必要要的缩写(printError优于printErr);避免使用类型关键字;使用习惯用语(init表示初始化,is/has返回布尔值);用反义词命名行为相反的函数

33. 不论是指针、引用类型仍是其天涯类型参数,都是值拷贝传递,区别在于拷贝的目标对象

34. 指针传递坏处在于延长该变量的声明周期,也可能致使他分配到堆上增长性能消耗

35. 函数参数在函数内部有效,做用域是整个函数内部

36. 变参  func test(a ...int){}   test(a[:]...)

37. 命名返回值的问题:  新定义的同名局部变量会引发同名遮蔽:xx is shadowed during return ;此时实名return便可

38. 闭包 匿名函数可以使用上下文的环境中的数据(最终数据)

39. 延迟调用defer 经常使用于资源释放 解除锁定 错误处理等 先入后出。 延迟调用开销很大,性能要求高压力大的算法尽可能避免使用

40. error是接口类型

41. panic会引起函数中断执行defer ,在defer中使用recover捕获panic提交的错误对象(recover只能在defer中执行才有效)

42. 多个panic仅最后一个被捕获

43. runtime/debug.PrintStrack()能够打印完整的堆栈信息

44. 不可恢复性、致使系统没法正常工做的错误才会使用panic (文件系统没权限操做、服务端口被占用、数据库未启动等)

45. 字符串是不可变字节(byte)序列,可用len获取长度,不可用cap; ` 支持跨行;容许字节数组访问,单不容许字节数组取地址

46.  用切片指向数组时,底层仍是指向该字符串

47. range遍历能够打印出汉字,len遍历出的汉字是乱码

48. append能够向[]byte追加  =》var bs []byte  bs=append(bs,"abc"...)

49. 字符串加法运算每次都会从新分配内存,构建大字符串性能极差;方法1:strings.Join  方法2:bytes.Buffer  小字符串拼接使用fmt.Sprintf text/template等

50. utf8.RuneCountInString(s)代替len获取带汉字的字符串长度

51. 长度是数组的类型组成部分,元素类型相同长度不一样的数组不是同一类型

52. 多维数组,只第一维支持... => [...][10]

53. 若是元素支持== !=操做,则数组也支持

54. 数组是值类型

55. 切片:不是动态数组或数组指针;内部经过指针引用底层数组,设定相关属性将数据读写操做限定在指定区域内。能够理解为数组指针的包装

56. 切片自己是只读对象,工做机制相似数组指针的包装   右半开区间  数组必须addressable

 

type slice struct{
    array unsafe.Pointer 
    len int
    cap int
}

57. 切片引用数组时,切片指针会指向数组地址;访问越界会报错;append会追加数组,当长度大于cap时会从新分配地址,则切片和数组就相互独立了

58. 切片 var a[]int 为nil,仅表明他为初始化,但依旧分配内存;且a[:]依旧是nil

59. 若是切片长时间占用大数组的少许数据,建议切片单独分配地址,以让大数组尽早释放

60. 可将字符串直接复制到[]byte  => b:=make([]byte,3) n:=copy(b,"abcdefhg")=>n=3,b=[97 98 99]

61. 字典的key必须支持== != 如数字、字符串、指针、数组、结构、接口

62. if v,ok:=m["d"];ok{存在} 使用ok-idiom模式判断key是否存在

63. delete(m,"d"),删除不存在的key不报错

64. map使用range迭代每次顺序不定

65. map被设计成 no addressable,全部无法修改value的成员(若是value是个结构或者数组等)  ;改进方法1:先获取完整value,修改后再赋值回去;方法2:value采用指针类型。由于value是指针,全部能够经过指针修改指针指向的数据。

66. map并发操做,某任务针对map写操做,其余任务对该map的读写删除都会致使进程崩溃;可用sync.RWMutex实现同步(不要使用defer)

67. map对象自己就是指针包装,传参不须要取地址

68. map建立时和slice同样要预选分配足够地址,减小扩张时没必要要的内存分配和从新哈希操做=>make(map[int]int,1000)

69. 对于海量小对象,应该直接用字典存储键值数据拷贝而不是指针,这样减小扫描对象的数量缩短垃圾回收时间。

70. 字典不会收缩内存,适当替换新对象是有必要的

71. 结构推荐命名初始化,以防扩充结构时报错
匿名结构:

u:=struct{
    name string
}{
    name:"xxx",
}

72. 只有全部成员都支持==操做时,结构才支持相等操做

73. 匿名字典隐式的以类型名为字段名称,使用时能够直接饮用匿名字段的成员,可是初始化时必须当作独立字段。(可是隐式字段是外部类型的话,隐式名称不包含包名)

74. 除接口指针 多级指针外的任何命名类型均可做为匿名类型

75. 字段标签是对字段描述的元数据,是类型的组成部分;运行期间可用反射获取标签信息,一般做为格式校验和数据库关系映射等

p1:=p{
    name:"xxx",
    sex:1,
}
v:=reflect.ValueOf(p1)
t:=v.Type()
for i,n:=0,t.NumField();i<n;i++{
    fmt.Printf("%s:%v\n",t.Field(i).Tag,v.Field(i))
}

76. reflect.StructTag提供了更完善的功能

77. 前置实例接收参数-receiver

78. receiver是基础类型则会被复制,指针类型则必须能获取实例地址

79. receiver类型选择:不修改的小对象或固定值用T;引用类型、字符串、函数等指针包装对象用T;修改实例状态用*T;包含Mutex等同步字段用*T,大对象或不肯定状况用*T;

80. 匿名类型的方法也存在同名遮蔽的特性。(可实现相似覆盖操做)

81. T的方法集是 receiver T;*T的方法集是receiver T+*T

82. 匿名嵌入S,T包含 receiver S;匿名嵌入*S,T包含 receiver S+*S; 匿名嵌入S或*S,*T都包含 receiver S+*S;

83. 方法集仅影响接口实现和方法表达式转换。匿名字段就是为方法集准备的

84. Chan:

一次性事件使用chan的close效率更高

向close的chan发数据panic

从已关闭的chan接收数据返回已缓存数据或零值

不管收发,nil通道都会阻塞

85. Chan和锁的选择:

同步问题应该用锁或原子变量来操做

对性能要求较高时,赢避免使用defer unlock

读写并发时,用RWMutex性能更好

对单个数据的读写保护建议使用读写锁

严格测试,尽量打开数据竞争检查

通道倾向于解决逻辑层次的并发处理架构

锁用来保护局部范围内的数据安全

86. FieldByName不支持多级名称,若有同名遮蔽须要匿名字段二级获取

87. 可用发射提取struct tag还能自动分解,经常使用于ORM映射或数据格式验证

88. 反射可经过Interface方法进行类型推断和转换

89. 对性能要求较高的地方须要谨慎使用反射

90. Go语言1.5版本实现的自举

相关文章
相关标签/搜索