Go学习笔记
一、数据结构
1.1 变量
1.1.1 变量数据类型
整型
类型 | 描述 |
---|---|
uint8 | 无符号 8位整型 (0 到 255) |
uint16 | 无符号 16位整型 (0 到 65535) |
uint32 | 无符号 32位整型 (0 到 4294967295) |
uint64 | 无符号 64位整型 (0 到 18446744073709551615) |
int8 | 有符号 8位整型 (-128 到 127) |
int16 | 有符号 16位整型 (-32768 到 32767) |
int32 | 有符号 32位整型 (-2147483648 到 2147483647) |
int64 | 有符号 64位整型 (-9223372036854775808 到 9223372036854775807) |
uint | 32位操作系统上就是uint32 ,64位操作系统上就是uint64 |
int | 32位操作系统上就是int32 ,64位操作系统上就是int64 |
uintptr | 无符号整型,用于存放一个指针 |
浮点型
类型 | 描述 |
---|---|
float32 | 32位浮点型 |
float64 | 64位浮点型 |
复数
var c complex64 = 1 + 2i
var d complex128 = 3 + 4i
类型 | 描述 |
---|---|
complex64 | 64位复数 |
complex128 | 128位复数 |
布尔值
var f bool = true
字符串
内部实现使用UTF-8
编码
var s1 string = "hello"
s2 := "你好"
1.1.2 变量声明方式
//方法一:声明一个变量 默认的值是0
var a int
//方法二:声明一个变量,初始化一个值
var b int = 100
//方法三:在初始化的时候,可以省去数据类型,通过值自动匹配当前的变量的数据类型
var c = 100
//方法四:(常用的方法) 省去var关键字,直接自动匹配(注:此方式不适用于全局变量)
e := 100
// 声明多个变量
var xx, yy int = 100, 200
var kk, ll = 100, "Aceld"
//多行的多变量声明
var (
vv int = 100
jj bool = true
)
1.1.3 常量、iota枚举
//常量(只读属性)
const a int = 10
//const 来定义枚举类型
const (
BEIJING = 10
SHANGHAI = 43
SHENZHEN = 32
)
const (
//可以在const() 添加一个关键字 iota, 每行的iota都会累加1, 第一行的iota的默认值是0
BEIJING = 10 * iota //iota = 0
SHANGHAI //iota = 1
SHENZHEN //iota = 2
)
const (
a, b = iota + 1, iota + 2 // iota = 0, a = iota + 1, b = iota + 2, a = 1, b = 2
c, d // iota = 1, c = iota + 1, d = iota + 2, c = 2, d = 3
e, f // iota = 2, e = iota + 1, f = iota + 2, e = 3, f = 4
g, h = iota * 2, iota * 3 // iota = 3, g = iota * 2, h = iota * 3, g = 6, h = 9
i, k // iota = 4, i = iota * 2, k = iota * 3 , i = 8, k = 12
)
1.2 数组和切片
1.2.1 声明
var arr1 [3]int //声明数组,初始化值为0
arr2 := [3]int{1, 2, 3} //声明时即初始化完成
arr3 := [...]int{1, 2, 3} //在编译期间通过源代码推导数组的大小
var slice1 []int //声明slice1是一个切片,但是并没有给slice分配空间
slice2 := []int{1, 2, 3} //声明slice2是一个切片,并且初始化,默认值是1,2,3。 长度len是3
slice3 := make([]int, 3) //len=3,cap=3
s := make([]int, 4, 5) //len=4,cap=5
s = append(s, 1) //len=5,cap=5
s = append(s, 1) //len=6,cap=10
1.2.2 传递
//值拷贝
func operate1(myArray [3]int) {
myArray[0] = 111
}
//引用拷贝
func operate2(myArray []int) {
myArray[0] = 111
}
arr1 := [3]int{1, 2, 3}
operate1(arr1) //[1,2,3]
arr2 := []int{1, 2, 3}
operate2(arr2) //[111,2,3]
s := []int{1, 2, 3} //len=3 cap=3 [1,2,3]
s1 := s[0:2] //左开右闭区间[0,2) len=2 cap=3 [1,2]
s1[0] = 100 //会将s一起修改 s=[100,2,3]
s2 := make([]int, 3) //s2 = [0,0,0]
copy(s2, s) //将s中的值依次拷贝到s2中
s2[0] = 400 //不会影响s中的值
1.3 map
var map1 map[string]string //声明map1是一种map类型,string->string,未分配空间时为nil
map1 = make(map[string]string, 10) //在使用map前,需要先用make给map分配数据空间
map2 := make(map[int]string)
map3 := map[string]string{
"one": "php",
"two": "c++",
"three": "python",
}
//引用传递
func ChangeValue(cityMap map[string]string) {
cityMap["England"] = "London"
}
func main() {
//声明
cityMap := make(map[string]string)
//添加
cityMap["China"] = "Beijing"
cityMap["Japan"] = "Tokyo"
cityMap["USA"] = "NewYork"
//遍历
for key, value := range cityMap {
fmt.Println("key = ", key)
fmt.Println("value = ", value)
}
//删除
delete(cityMap, "China")
//修改
cityMap["USA"] = "DC"
//方法调用
ChangeValue(cityMap)
}
二、方法
2.1 形参
func foo1(a string, b int) {}
func foo1(a string, b int) int {
return 3
}
2.2 返回值
1- 返回单个返回值
func foo1(a string, b int) int {
return 3
}
2- 返回多个返回值,匿名的
func foo2(a string, b int) (int, int) {
return 666, 777
}
3- 返回多个返回值, 有形参名称的
func foo3(b int) (r1 int, r2 int) {
//r1 r2 属于foo3的形参, 初始化默认的值是0
//r1 r2 作用域空间 是foo3 整个函数体的{}空间
fmt.Println("r1 = ", r1)
fmt.Println("r2 = ", r2)
//给有名称的返回值变量赋值
r1 = b
r2 = b + 10
return
}
func foo4(b int) (r1, r2 int) {
r1 = b
r2 = b + 2000
return
}
三、对象
3.1 封装
type User struct {
// 变量名首字母大写,说明其他包可以访问
Name string
Age int
}
func (this *User) Show() {
fmt.Println("名字:", this.Name)
fmt.Println("年龄:", this.Age)
}
func (this *User) GetName() string {
return this.Name
}
func (this *User) SetName(name string) {
this.Name = name
}
func main() {
user := User{"jack", 18}
user.SetName("tom")
user.Show()
}
3.2 封装
type User struct {
Name string
Age int
}
type Student struct {
User // 继承父类User
Class string
}
func main() {
user := User{"jack", 18}
student := Student{user, "六班"}
fmt.Println(student)
}
3.3 多态
//接口父类
type User interface {
GetName() string
SetName(name string)
}
//实现接口全部方法的子类
type Student struct {
Name string
}
func (this *Student) GetName() string {
return this.Name
}
func (this *Student) SetName(name string) {
this.Name = name
}
func main() {
var u User
u = &Student{"tom"}
fmt.Println(u.GetName())
}
interface{}空接口
int 、string、float32、 float64、struct .... 都实现了interface{}
就可以⽤interface{}类型 引⽤任意的数据类型
func main() {
var x interface{} = "djj"
value, ok := x.(string)
if !ok {
fmt.Println("x is not string")
} else {
fmt.Printf("%v %T", value, value)
}
}
四、并发编程
4.1 goroutine
runtime.Goexit()
会退出当前goroutine,结束全部方法
go func() {
defer fmt.Println("defer A")
func() {
defer fmt.Println("defer B")
runtime.Goexit()
fmt.Println("==B==")
}()
fmt.Println("==A==")
}()
---
defer B
defer A
4.2 Channel
Channel是goroutine之间交换信息的媒介
上图中的两个 Goroutine,一个会向 Channel 中发送数据,另一个会从 Channel 中接收数据,它们两者能够独立运行并不存在直接关联,但是能通过 Channel 间接完成通信。
定义方式
make(chan Type) //等价于make(chan Type, 0)
make(chan Type, capacity)
使用方式
channel <- value //将value发送到channel
<- channel //接收并将其丢弃
x := <- channel //接收并将其赋值给x
x, ok := <-channel //功能同上,同时检查通道是否已关闭或是否为空
channel := make(chan int, 1)
channel <- 3
go func() {
x := <-channel
fmt.Println("==", x)
}()
无缓冲vs有缓冲
无缓冲通道,在收发信息时会阻塞。
有缓冲通道,在消息满或空时才会阻塞。
关闭channel
- channel不像⽂件⼀样需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的,才去关闭channel;
- 关闭channel后,⽆法向channel 再发送数据(引发 panic 错误后导致接收⽴即返回零值)
- 关闭channel后,可以继续从channel接收数据;
func main() {
channel := make(chan int)
go func() {
for i := 0; i < 5; i++ {
channel <- i
fmt.Println("写入", i)
}
//关闭channel
close(channel)
}()
for {
if value, ok := <-channel; ok {
fmt.Println("接收", value)
} else {
fmt.Println("channel已关闭")
break
}
}
}
channel与range
func main() {
channel := make(chan int)
go func() {
for i := 0; i < 5; i++ {
channel <- i
fmt.Println("写入", i)
}
//关闭channel
close(channel)
}()
for data := range channel {
fmt.Println("接收", data)
}
}
channel与select
末、杂七杂八
1-导包
初始化方式是递归初始化,初始化一个包时会先初始化全局变量,然后执行init()方法
导包的三种方式
import _ "fmt" //匿名导入, ⽆法使⽤当前包的⽅法,但是会执⾏当前的包内部的init()⽅法
import aa "fmt" //给fmt包起⼀个别名,可通过aa.Println()来直接调⽤
import . "fmt" //导入fmt包中的全部⽅法,可以直接使⽤API来调⽤,不需要fmt.API来调⽤
2-指针
func swap(pa *int, pb *int) {
var temp int
temp = *pa //temp = main::a
*pa = *pb // main::a = main::b
*pb = temp // main::b = temp
}
func main() {
var a int = 10
var b int = 20
swap(&a, &b)
}
3-defer
defer会按顺序压入栈中,函数结束后再依次取出
func main() {
defer fmt.Println("main end1")
defer fmt.Println("main end2")
fmt.Println("main::hello go 1")
fmt.Println("main::hello go 2")
}
----
main::hello go 1
main::hello go 2
main end2
main end1
return语句先执行,defer语句后执行
func f1() int {
fmt.Println("return func")
return 3
}
func f2() {
fmt.Println("defer func")
}
func f3() int {
defer f2()
return f1()
}
func main() {
f3()
}
---
return func
defer func
4-反射
变量结构
reflect包
func main() {
var x interface{} = "djj"
fmt.Printf("%T %v\n", reflect.TypeOf(x), reflect.TypeOf(x))
fmt.Printf("%T %v", reflect.ValueOf(x), reflect.ValueOf(x))
}
---
*reflect.rtype string
reflect.Value djj
5-结构体标签
常见应用:json编解码,orm映射关系
type User struct {
Name string `info:"name" doc:"aa"`
Age int `info:"age"`
}
func main() {
var u interface{} = &User{"tom", 17}
fields := reflect.TypeOf(u).Elem()
for i := 0; i < fields.NumField(); i++ {
tagInfo := fields.Field(i).Tag.Get("info")
tagDoc := fields.Field(i).Tag.Get("doc")
fmt.Printf("info:%v doc:%v\n", tagInfo, tagDoc)
}
}
Comments | 0 条评论