只记一:
声明类型+初始化:var num2 float32 = 0.32
永远都是变量名在前 数据类型在后
1. 基本类型声明有默认值:
2. 结构体声明不会为nil
:
3. 四大引用类型可为nil
【而make函数专门实例化引用数据类型】
4. 指针类型可为nil
【而new函数专门实例化指针类型】
只记二:
切片、map、channel的变量名直面的是变量值的地址集合(下图中第二行结构),通过地址集合操作变量值(通过地址的操作过程被Go封装了),所以对变量的传递是对变量地址集合的拷贝!
注:如果函数更改了变量对应的地址集合中数据,则必须return
新的地址集合!
如:函数真的在数据后添加了一个元素2,但它肯定有修改地址集合中的 size
,所以我们需要把新的地址集合返回让其刷新!
func addSlice(s []int) []int {
s = append(s, 2)
return s
}
数据类型转换
数据类型转换为:T(表达式)
比如:chars := []rune(str)
字符串转换为字节切片
基本数据类型
布尔型
bool
:true /false 不能参与基本数据类型的运算和转换
整型(%b
%o
%d
%x
)
整型是按字节数分的:int8
int16
int32
int64
对应的无符号整型:uint8
uint16
uint32
uint64
实际int
uint
是不存在的,但int
uint
会根据不同平台分别对应不同整型(32 / 64 位)
注:整型 :=
默认推导为 ===> int
浮点型(%f
%.2f
)
float32
、 float64
注:浮点型 :=
根据系统位数推导为 ===> float32
或 float64
字符串(%s
)
string
- 双引号
- 反引号可以原样输出
- 采用UTF-8编码(可以通过
rune
类型对每个utf-8字符访问)
字符(%c
)
byte
:一个字节,底层是 uint8;(只支持ASCLL编码)
rune
:四个字节,底层是 int32。(支持UTF-8编码 注:UTF-8兼容ASCLL,UTF-8中汉字一般需要3个及以上个字节)
注:字符型 :=
默认推导为 ===> int32
(rune)
数组
数组是存储相同类型数据的固定连续区域。
数组声明必须确定数组大小
和var声明变量类型类似:声明大小 ||
初始化
普通声明
var 变量名 [数组大小]T
初始化声明
变量名 接受 [...]T{1,2,3}
(编译器可以推到出数组大小)
遍历数组
fori:(回想string类型也可以直接用下标是按byte取的!)
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
forr:(而string遍历用forr是按rune取的!)
for 下标, c := range a {
fmt.Println(c)
}
派生类型
切片 (slice) :类似Java中ArrayList用法!不适合大量查找、删除操作!
动态地分配大小的连续内存空间:
切片的生成
从连续内存中生成切片!
一、从数组
数组名[起始位置 : 结束位置]
(左闭右开)【起始位置缺省则表示从头,结束位置缺省则表示到结尾】
var a = [...]int{1,2,3} //数组
fmt.Printf("%T",a) //[3]int
s := a[1:2] // 切片
fmt.Printf("s=%v s类型:%T",s,s) //s=[2] s类型:[]int
重置切片:a[0:0]
二、声明切片
普通声明
var 切片名 []T
(不会分配数据内存,是nil
)
初始化声明
- 变量名 接受
[]T{1,2}
([]
中没有任何值的数组声明就是切片声明) - 变量名 接受
make([]T,size,cap)
(最最常用!!!)
size
:初始化定义的变量个数
cap
:预分配的元素数量,这个值设定后不影响size(该扩容还是得扩容),只是能提前分配空间,降低多次分配空间造成的性能问题。
ss := make([]int,2,3) 或 ss := make([]int,2)【此时size == cap】
ss = append(ss, 1,2,3,4,5,6,7,8)
fmt.Printf("ss类型:%T ss=%v",ss,ss) /ss类型:[]int ss=[0 0 1 2 3 4 5 6 7 8] 该扩容还是会扩容
append()
函数为切片添加元素
s1 := make([]int,2,4)
s1 = append(s1,1,2)
s2 := make([]int,0,4)
s2 = append(s2, s1...) /将s1全部追加给说s2
s2 = append(s2, s1[0:2]...) /注意s1[0:2]仍然是个切片
扩容: 当超过cap
时会进行二倍扩容,如果没有初始则1、2、4、8、16……
注:就是二倍扩容,与2得整数幂没关系
copy()
函数拷贝切片数据
因为切片变量传递拷贝的是地址集合,当想要拷贝数据时,就需要copy()
函数!
- 最多copy到
dst
切片的size,不会跨越size! - 并且默认从头覆盖
dst
中数据!
src := []int{1,2,3,4}
dst := make([]int,2,4)
copy(dst,src)
fmt.Println(dst) /[1 2]
src := []int{1,2,3,4}
dst := make([]int,2,4)
copy(dst[1:],src)
fmt.Println(dst) /[0 1]
怎样删除切片中一个数据呢?
没有专门的删除函数:
src := []int{1,2,3,4}
// 删除第三个元素
src = append(src[0:2],src[3:]... )
fmt.Println(src) /[1 2 4]
遍历切片
因为切片和数组一样都可以用下标访问元素,所以和数组一样遍历:fori 或 forr
排序:sort只能对切片排序
src := []int{2,4,1,5}
sort.Ints(src)
将数组转换成切片即可:
sort.Ints(a[:])
- TIPS: 数组和切片的区别
数组 | 切片 | |
---|---|---|
定义 | 固定的连续内存数据 | 动态的连续内存数据 |
声明 | 一定要声明自己的大小: [3] 或 [...] | 没有固定大小:[] |
类型%T | [3]int | []int |
变量名面向 | 数据值 | 数据的地址 |
nil ? | 面对的数据至少有默认值,与 nil 无关! | 面对的地址可能没有,可能为nil ! var 切片名 []T 方式声明切片并不会给分配内存空间! |
len(s) | 返回数组的容量大小 | 返回切片中有效数值个数size |
映射 (map):类似Java中HashMap!适合大量的查找工作!
map的声明:map[keyType]valueType)
普通声明
var 变量名 map[keyType]valueType
(不会分配数据内存,是nil
)
初始化声明
- 变量名 接受
map[keyType]valueType{k1:v1,k2:v2}
- 变量名 接受
make(map[keyType]valueType)
添加与获取元素
不存在会返回默认值:
m := make(map[string]int)
m["id"] = 2001
fmt.Println(m["id"]) /2001
fmt.Println(m["name"]) /0
但其实获取元素时会将是否存在作为第二个元素返回:
v,ok := m["name"]
if ok {
fmt.Println(v)
}else {
fmt.Println("不存在")
}
删除元素
delete(map,键)
遍历map
因为map是没有下标的,所以只能是 forr:(当然,散列表坑定是无序输出)
mm := map[string]int{"id":1,"name":2001,"age":520}
for k, v := range mm {
fmt.Println(k,v)
}
sync.Map
:并发安全的map
sync.Map
声明都会初始化(结构体与nil
无关)
var map名 sync.Map
或 变量名 接受 sync.Map{各种参数(可以不写)}
操作函数
声明:
var m sync.Map
添加元素:m.Store(k,v)
m.Store(1,1111)
查找元素:m.Load(k)
v,ok := m.Load(1)
if ok {
fmt.Println(v)
}else {
fmt.Println("不存在")
}
删除元素:m.Delete(k)
m.Delete(1)
遍历
注意:sync.Map
对象可以存储任何混合存储各种类型的 kye、value
var mm sync.Map
fmt.Println(mm)
mm.Store(1,1111)
mm.Store(2.1,2222)
mm.Store("3",3333)
mm.Range(func(k, v interface{}) bool {
fmt.Println("iterate:",k,v)
return true
})
列表(list):类似Java中的LinkedList!可以快速增删的非连续数据!
Go将列表使用container/list包来实现,内部的实现原理是双链表。列表能够高效地进行任意位置的元素插入和删除操作。
声明都会初始化(结构体与nil
无关)
l := list.New()
或 var ll list.List
都会初始化,且两种方法的初始化效果都是一致的。
PushXxx
插入元素:任意类型元素
var ll list.List
ll.PushFront("first")
ll.PushBack(0)
Remove
删除目标元素
列表的插入函数的返回值会提供一个*list.Element结构,这个结构记录着列表元素的值及和其他节点之间的关系等信息。从列表中删除元素时,需要用到这个结构进行快速删除。
PushXxx
返回 *list.Element
结构
注:只能通过得到 *list.Element结构 而操作列表中的数据!
fori
+l.Front()
遍历
l.Front()
返回 *list.Element
结构
var ll list.List
ll.PushBack(0)
ll.PushBack(1)
for i := ll.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}