1 基础语法
1.1 变量与常量
//var 变量名 类型 = 表达式(在函数内部,可以使用更简略的 :=)
var m int = 100
m := 100
//const 常量名 类型 = 表达式(常量在定义的时候必须赋值)
const pi = 3.1415
- 支持批量声明;
- 变量的类型可以省略;
- 在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量;
- iota在const关键字出现时将被重置为0,const中每新增一行常量声明将使iota计数一次;
1.2 基本数据类型与运算符
1.2.1 常用类型
| 类型 | | | —- | —- | | 整形 | 按长度划分为(无符号对应uint)
int8、int16、int32、int64 | | 浮点型 | float32和float64 | | 布尔值 | 默认值为false,不允许整型强制转换为布尔型 | | 字符串 | Go语言中的字符串以原生数据类型 |
1.2.2 运算符
1.2.3类型别名与自定义类型
//将MyInt定义为int类型
type MyInt int
//系统默认的类型别名
type byte = uint8
type rune = int32
通过type关键字的定义,MyInt就是一种新的类型,它具有int的特性
类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。
1.3 流程控制
1.3.1 if
if条件判断与其他语言基本一致。
但有一种特殊的写法,在 if 表达式之前添加一个执行语句,再根据变量值进行判断。
a := 10
if a >= 10 {
fmt.Println("OK")
}
//这里的a,if外获取不到
if a := 10; a >= 10 {
fmt.Println("OK")
}
1.3.2 for
for循环的基本格式,只有循环体就相当与while(true)
for 初始语句;条件表达式;结束语句{
循环体语句
}
for range(键值循环)
- 数组、切片、字符串返回索引和值。
- map返回键和值。
- 通道(channel)只返回通道内的值。
1.3.3 swith
Go语言规定每个switch只能有一个default分支;
fallthrough语法可以执行满足条件的case的下一个case;
1.4 数组
1.4.1 定义和初始化
//var 数组变量名 [元素数量]T
//会初始化为int类型的零值
var a [3]int
//使用指定的初始值完成初始化
var b = [3]int{1, 2}
//编译器会根据初始值的个数自行推断数组的长度
var numArray = [...]int{1, 2}
//指定索引值的方式来初始化数组
a := [...]int{1: 1, 3: 5}
注:数组是值类型
1.5 切片
1.5.1 定义和初始化
切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。切片是一个引用类型。
//不指定元素数量的数组就是切片
var slice []T
1.5.2 切片表达式
切片表达式从字符串、数组、指向数组或切片的指针构造子字符串或切片。
切片表达式中的low和high表示一个索引范围(左包含,右不包含)
//简单的表达式可以省略max,容量等于得到的切片的底层数组的容量。
a[low : high : max]
1.6 Map
1.6.1 定义和初始化
//var Map变量名 map [key_data_type] value_data_type
//普通的声,会创建一个 nil map。nil map 不能用来存放键值对
var map_variable map[key_data_type]value_data_type
//使用make()函数来分配内存
map_variable := make(map[key_data_type]value_data_type)
1.6.2 判断是否存在某个键
//ok是看当前key是否存在返回布尔,value返回对应key的值
value, ok := map[key]
1.7 函数
1.7.1 定义
func 函数名(参数)(返回值){
函数体
}
//凡是满足 func(int, int) int的函数都可以赋值给c
type calculation func(int, int) int
var c calculation
- 函数的参数中如果相邻变量的类型相同,则可以省略类型
- 函数支持多返回值
- 函数可以定义为类型,赋值于某个变量
- 函数可以做为参数,也可以做为返回值
1.7.2 匿名函数
func main() {
// 将匿名函数保存到变量
add := func(x, y int) {
fmt.Println(x + y)
}
add(10, 20) // 通过变量调用匿名函数
//自执行函数:匿名函数定义完加()直接执行
func(x, y int) {
fmt.Println(x + y)
}(10, 20)
}
匿名函数因为没有函数名,所以没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数
1.7.3 闭包
闭包=函数+引用环境
func add (x int) func(int) int {
return func(y int) int {
x += y
return x
}
}
1.7.4 内置函数
函数 | 作用 |
---|---|
len | 来求长度,比如string、array、slice、map、channel ,返回长度 |
cap | 用于返回某个类型的最大容量(只能用于切片和 map) |
append | 用来追加元素到数组、slice中,返回修改后的数组、slice |
delete | 从map中删除key对应的value |
close | 主要用来关闭channel |
panic/recover | Go语言没有异常机制,配合defer用来做错误处理 |
make | 用来分配内存,返回Type本身(只能应用于slice, map, channel) |
new | 用来分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针 |
init | 不接收任何参数也没有任何返回值,我们也不能在代码中主动调用它。当程序启动的时候,init函数会按照它们声明的顺序自动执行。 |
1.8 指针
&(取地址)和(根据地址取值),取地址操作符&和取值操作符是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
func main() {
a := 10
b := &a
fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
fmt.Println(&b) // 0xc00000e018
c := *b // 指针取值(根据指针去内存取值
fmt.Println(c) //c:10
}
- 对变量进行取地址(&)操作,可以获得这个变量的指针变量。
- 指针变量的值是指针地址。
- 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。
1.9 结构体
1.9.1 定义与实例化
//使用type和struct关键字来定义结构体
type 类型名 struct {
字段名 字段类型
字段名 字段类型
…
}
//使用var实例化,使用键值对对结构体进行初始化
func main() {
var p 类型名
var p2 类型名{
字段名: 值,
字段名: 值,
字段名: 值,
}
//通过.来访问结构体的字段(成员变量)
p2.字段名
}
注:结构体中字段大写开头表示可公开访问,小写表示私有
1.9.2 方法和接收者
Go语言中的方法(Method)是一种作用于特定类型变量的函数。方法与函数的区别是,函数不属于任何类型,方法属于特定的类型。
/*func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
函数体
}*/
//Person 结构体
type Person struct {
name string
age int8
}
//NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
return &Person{
name: name,
age: age,
}
}
//注意指针类型的接收者和值类型接收者的区别
func (p Person) methodA() {
}
func (p *Person) methodB() {
}
1.9.3 结构体的“继承”
go中没有继承,只能通过组合来实现继承。
- 一个struct嵌套了另外一个匿名的struct从而实现了继承,嵌套多个匿名struct实现多重继承。
- 一个struct嵌套了宁外一个struct的实例实现了组合。 ```go type Animal struct {
}
//继承 type Cat struct { //匿名 *Animail }
//组合 type Dog struct { animal Animal }
<a name="nrUzT"></a>
####
<a name="wbTcU"></a>
#### 1.9.4 结构体标签
Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。 Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:
```go
type Student struct {
ID int `json:"id"` //通过指定tag实现json序列化该字段时的key
Gender string
name string
}
1.10 包
1.10.1 定义与引入
一个包可以简单理解为一个存放.go文件的文件夹。该文件夹下面的所有.go文件都要在非注释的第一行添加如下声明,声明该文件归属的包。
要在当前包中使用另外一个包的内容就需要使用import关键字引入这个包,并且import语句通常放在文件的开头,package声明语句的下方
package packagename
import importname "path/to/package"
importname 可以省略
importname 的包名如果为 _
作为包名,那么这个包的引入方式就称为匿名引入。一个包被匿名引入的目的主要是为了加载这个包,从而使得这个包中的资源得以初始化。 被匿名引入的包中的init
函数将被执行并且仅执行一遍。
1.10.2 go model
1.11 接口
1.11.1 接口的定义与实现
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
接口就是规定了一个需要实现的方法列表,在 Go 语言中一个类型只要实现了接口中规定的所有方法,那么我们就称它实现了这个接口。
- 空接口是指没有定义任何方法的接口类型。因此任何类型都可以视为实现了空接口。
- 由于接口类型的值可以是任意一个实现了该接口的类型值,所以接口值除了需要记录具体值之外,还需要记录这个值属于的类型
1.11.2 ERROR接口
1.12 反射
1.12.1 reflect包
reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type
func reflectValue(x interface{}) {
v := reflect.ValueOf(x)
k := v.Kind()
switch k {
case reflect.Int64:
// v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换
fmt.Printf("type is int64, value is %d\n", int64(v.Int()))
case reflect.Float32:
// v.Float()从反射中获取浮点型的原始值,然后通过float32()强制类型转换
fmt.Printf("type is float32, value is %f\n", float32(v.Float()))
case reflect.Float64:
// v.Float()从反射中获取浮点型的原始值,然后通过float64()强制类型转换
fmt.Printf("type is float64, value is %f\n", float64(v.Float()))
}
}
func main() {
var a float32 = 3.14
var b int64 = 100
reflectValue(a) // type is float32, value is 3.140000
reflectValue(b) // type is int64, value is 100
// 将int类型的原始值转换为reflect.Value类型
c := reflect.ValueOf(10)
fmt.Printf("type c :%T\n", c) // type c :reflect.Value
}
1.12.2 结构体反射
type student struct {
Name string `json:"name"`
Score int `json:"score"`
}
func main() {
stu1 := student{
Name: "小王子",
Score: 90,
}
t := reflect.TypeOf(stu1)
fmt.Println(t.Name(), t.Kind()) // student struct
// 通过for循环遍历结构体的所有字段信息
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))
}
// 通过字段名获取指定结构体字段信息
if scoreField, ok := t.FieldByName("Score"); ok {
fmt.Printf("name:%s index:%d type:%v json tag:%v\n", scoreField.Name, scoreField.Index, scoreField.Type, scoreField.Tag.Get("json"))
}
}