变量声明
var 变量名 变量类型
变量初始化
var v1 int = 10
var v2 = 10
v3 := 10
出现在冒号左侧的不应该是被声明过的变量,而且这种简短声明只能出现在函数中
变量赋值
可以采用多重赋值 i, j = x, y
匿名变量
函数返回多个值,如果值想获得其中的某些可以使用 __, __, nickname := GetName()
字面常量
硬编码的常量,不用像c语言一样在末尾加上L来区别是int还是long,go中字面常量是无类型的,只要这个常量在相应类型值域范围内,就可作为该类型常量
常量定义
通过const关键字来定义
也可以是无类型的
编译期确定,所以右值不能是执行期才确定值的表达式
预定义常量
true,false,iota
itoa在每一个const关键字出现时被置为0,下一个const出现之前,每出现一次iota,其代表的数字会自动加1
枚举
通过const后紧跟一对圆括号定义一组常量,而没有关键字enum
const (
Sunday = iota
Monday
...
)
同Go语言的其他符号一样,以大写字母开头的常量在包外可见
基础类型
复合类型
布尔
不支持其他类型赋值,不能自动或强制类型转换
整型
复数类型
字符串
c/c++中不存在原生字符串,而是使用字符数组,通过字符指针来传递
var str1 string声明一个字符串
可以像数组一样用下标访问,但是初始化之后的字符串不能修改
字符串中包含非ASNI的字符,比如中文,则必须把源码保存为UTF-8格式
连接操作 x + y
获取长度 len(s)
取字符 s[i]
for i : =0; i < n; i++ {
} 以字节数组的方式遍历
for i, ch := range str {
} 以unicode字符遍历,此时ch类型为rune
声明多行字符串时使用"`",它没有字符转义,换行也将输出
字符类型
byte代表utf-8中单个字节,rune代表unicode中单个字符 出于简化的考虑,多少api假设字符串为utf-8编码,使用unicode的较少
数组
[2*N]struct {x, y int32} 类型数组
[1000]*float64 指针数组
[3][5]二维数组
数组长度定义后不可修改,声明时可以使用常量或者常量表达式
可以使用...省略号声明一个数组,go语言会自动根据元素个数计算长度,但是中括号不能为空,那样就是slice了
len()获取长度
可以通过下标访问
也可以通过for i, v := range array {} 的方式访问
数组是一个值类型,传递参数时会发生一次拷贝,函数中使用的也是副本
数组切片
三组切片的数据结构包含三个变量:一个指向原生数组的指针,数组切片中的元素个数,切片已分配的存储空间
slice并不是真正的动态数组,而是一个引用类型
基于数据创建切片 myArrary[first:last],基于数组全部创建切片 myArray[:]
直接创建 mySlice1 := make([]int, 5, 10) 创建初始元素个数为5,元素初始值 0,并预留10个存储空间
mySlice3 := [int{1,2,3,4,5}] 直接初始化5个元素的数组切片,会有一个匿名的数组被创建
for i := 0; i < len(myArray); i++ 逐一遍历
或者使用range关键字 for i, v := range mySlice 遍历
cap() 返回切片空间大小, len()返回元素个数
mySlice = append(mySlice, 1,2,3) 尾部追加,并生成新的切片
mySlice = append(mySlice, mySlice2...) 省略号是必须的,append语义是从第二个参数开始是追加的元素,省略号的作用是把 mySlice2所有元素打散传入
newSlice := oldSlice[:] 基于oldSlice创建新的splice 选择的范围不能超过oldslice的cap()值,超过len的部分填充为0
通过copy来复制一个slice到另一个slice,两个不一样大小,以较小的元素个数进行复制
append的函数会改变slice所引用的数组内容,从而影响引用同一数组的其他slice。但当slice中没有剩余空间时,此时将动态分配新的数组空间。返回的slice数组指针指向这个空间,而原数组的内容将保持不变,其他引用此数组的slice不受影响。
map
声明一个map :var 变量名 map[key类型] value类型,这种声明方式需要在使用之前通过make初始化
map的key可以是所有完全定义了==或者!=操作的类型
可以通过make动态创建 myMap = make(map[key类型] value类型)
创建时初始化 myMap = map[string] PersonInfo { "1234" : PersonInfo{}, }
myMap["1234"] = PersonInfo{} 赋值
元素删除 delete(myMap, "1234") 元素不存在不会有什么问题
value, ok := myMap["1234"]
if ok {
} 这种方式进行查找
map是无序的,每次打印的map都会不一样,,只能通过key获取,不能通过index获取
map长度是不固定的,和slice一样,也是引用类型
len函数返回map拥有的key的数量
make和new的区别
make只能创建slice、map和channel,并且返回一个有 初始值(非零)的T类型,而不是*T。
new分配了零值填充的T类型的内存空间,并且返回其地址,即一个*T类型的值。
这是因为指向数据结构的引用在使用前必须被初始化,例如slice使用前必须初始化他引用的数组。
问题:通过下标返回的值是拷贝,还是引用?
条件语句
条件不需要小括号
无论语句体内有几条语句,花括号是必须的
左花括号必须与if或else同一行
if之后,条件语句之前,可以添加变量初始化语句,使用分号(;) 分割
在有返回值的函数中,不允许在if else中return,go编译器找不到终止该函数的return语句
错误的例子:
func example(x int) int {
if x == 0 {
return 5
} else{
return x
}
}
选择语句
左花括号必须和switch同一行
条件表达式不限制为常量或者整数
单个case中,恶意出现多个结果选项
不需要break来明确退出一个case
只有在case中明确添加fallthrough才会继续执行下一个case
可以不设定switch之后的表达式,整个switch和多个if else的逻辑作用相同
循环语句
左花括号必须和for同一行
可以在条件表达式中初始化变量或赋值,多个变量赋值时,只允许使用平行赋值的方式(i,j,k := 1, 2, 3而不是i := 1, j := 2, k := 3)
支持continue和break, break有更高级的用法,可以决定跳出哪曾循环
跳转语句
goto 跳转到某个标签
函数
函数基本组成:关键字func,函数名,参数列表,返回值,函数体和返回语句
参数列表和返回值中,多个变量类型相同可以合并,例如func Add(a,b int)
通过import导入函数所在的包,小写字母开头的函数只在本包中可见,大写字母开头的函数才能被其他包使用
通过(...type) 传递不定参数,通过for _, arg := range args 来提取不定参数
函数中调用了其他不定参数的函数,可以原样传递参数,也可以使用切片
func myfunc(args ...int) {
myfunc3(args ...)
myfunc3(args[1:]...)
}
要传递任意类型的不定参数,只要将之前的type替换为interface{}
func Printf(format string, args ...interface{}) { }
通过arg.(type)获取参数的类型:
func MyPrintf(args ...interface{}) {
for _, arg := range args {
switch arg.(type) {
case int:
case string:
case int64:
default:
}
}
}
多返回值,返回值可以命名,在函数开始的时候初始化为空,在return不带任何参数时,会返回对应的返回值变量的值(类似于传出参数),多个返回值之间用“,”分割,如果函数是首字母大写的,那么建议命名返回值变量,这样有利于生成我文档
传递指针,注意string、slice、map这三种类型的实现类似指针,可以直接传递,但函数如果修改slice长度,则仍需传递slice指针
不关注某个返回值,可以使用下划线来跳过这个返回值
函数可以通过type typeName func(input intputType...)(resutlt resultType)的方式来定义类型
匿名函数可以像变量一样传递,
匿名函数也可以直接调用,在函数体最后的右花括号后面紧跟参数列表
闭包
基本概念:闭包是可以包含自由变量的代码快,这些变量不再这个代码快内或者任何全局上下文中定义,而在定义代码快的环境中定义。要执行的代码快(由于自由变量包含在代码快中,所以这些自由变量以及她们引用的对象没有
被释放)为自由变量提供绑定的计算环境
价值:函数作为对象,保存在变量中,通过参数传递给其他函数
我的理解,类似与C++中的仿函数对象,只是不需要命名,在外部函数中定义变量,调用外部函数返回内部函数,内部函数访问了外部函数中定义的变量,因为有引用所以不能被回收,
error接口
type error interface {
Error() string
}
自定义error类型
type PathError struct {
Op string
Path string
Err error
}
实现Error方法
func (e *PathError) Error() string {
return e.Op + " " + e.Path + ": " + e.Err.Error()
}
defer 语句遵循先进后出的原则,最后定义的defer先被执行
func panic(interface()) 正常流程终止,执行defer语句,执行完毕后返回到调用函数,并逐层向上执行panic,直至所属goroutine中所有正在执行的含数据终止
func recover() interface() 用于终止错误处理流程,一般应该在defer中调用,截取错误处理流程。在未发生一场的goroutine中明确调用回复过程,会导致该gorutinue所属的进程打印影厂信息后直接退出
panic作为最后的手段,代码中应该没有或者少有panic
init函数可用于所有package,main只能用于package main
建议每个package仅使用一个init函数,尽管可以使用多个,但是从可读性角度来说使用一个i
init和main由go自动调用
init是可选的,但是main是必须的
程序初始化和执行起始于main包,编译时依次导入依赖包,并初始化包级常量和变量,调用包的init函数,每个包之后被导入一次,等所有导入的包都加载完毕,初始化main包中的常量和变量,调用main的init函数,最后执行main函数
可以使用相对路径和绝对路径,绝对路径从gopath/src之后的路径开始
点操作
import (
. "fmt"
)
这种方式导入包,使用时可以省略包名
别名操作
import (
f "fmt"
)
使用时可以用别名代替包名
_操作
import (
_ "githup.com/ziutek/mymysql/godrv"
)
引入该包,不直接使用包里的函数,而是调用了该包的init函数