记录一下自己的学习过程,顺带水一篇文章
go语言基础变量类型
变量定义
var a int/float32/float64/string/bool/... = value
var b := value //自动确定类型
var c [3][4] int //2维int型数组
interface{}//存储任意类型
//可以只声明不赋值,数值类型默认为0 布尔类型默认为false 字符串为"" 其他基本为nil
nil
nil 是一个预先声明的标识符,指针、通道、函数、接口、map、切片的零值就是nil
nil 是没有默认类型的,他的类型具有不确定性,我们在使用它时必须要提供足够的信息能够让编译器推断 nil 期望的类型
以下是 nil 的一些注意事项:
1. 声明一个 nil 的 map,map 可以读数据,但是不能写数据
2. 关闭一个 nil 的 channel 会引发 panic
3. nil切片不能进行索引访问,会引发 panic
4. 方法接收者为 nil 时,如果在方法内使用到了会引发 panic
5. 空指针一个没有任何值的指针
切片(变长数组)
切片的声明
var s1 []int //会被初始化维nil
s2 := []int{} //不为nil,为空
var s3 []int = make([]int, 0, 0) //参数分别为,make类型,初始长度,缓存大小 不为nil,为空
arr := [5]int{1, 2, 3, 4, 5} //数组
var s6 []int //切片
s6 = arr[1:4] //从数组切片 切片是数组的一个引用
s7 = arr[:3:8] //s7切片arr的0-2,并切cap设置为8(最多存放8个数据 0-7)
s8 [][]int{ //[]int类型的切片 2维变长数组
[]int{1, 2, 3}, //初始化值
[]int{100, 200},
[]int{11, 22, 33, 44},
}
切片的读写
data := [...]int{0, 1, 2, 3, 4, 5}
s := data[2:4]
s[0] += 100
结果是 data 的数据改变了。切片的一切修改都是在底层数组上的修改( make 创建的切片会自动分配一个数组)
切片的函数 append/copy
var a = []int{1, 2, 3}
b := append(a,4) //b:{1,2,3,4} append 添加元素
c := make([]int,3)
copy(c,a) //将a的内容拷贝到c 这是深拷贝,c的修改不会影响a
d := a //用a给d赋值,这是浅拷贝,d的修改会影响a
切片/数组遍历 range
data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := data[:]
for index, value := range slice {
fmt.Printf(index, value)
}
map
map 声明
map[KeyType]ValueType//{可以添加数据} //不添加会被初始化为nil
make(map[KeyType]ValueType, 0) //初始大小为0的map 不为nil
map的增删改查
a := make(map[string]int, 8)
a["DLUT"] = 985 //添加 DLUT 985
a["DLUT-开发区"] = 985
a["DLUT-开发区"] = 211 //修改键值对
delete(a,"DLUT-开发区") //删除 DLUT-开发区 211
v,ok = a["DLUT"] //查找DLUT对应的值,如果有则ok为true,v为对应的值 否则ok为false,v为对应类型的0值
map的遍历
scoreMap := make(map[string]int)
scoreMap["张三"] = 90
scoreMap["小明"] = 100
scoreMap["娜扎"] = 60
for k, v := range scoreMap {
fmt.Println(k, v) //顺序不确定
}
//以下是根据key值大小排序的遍历
var keys = make([]string, 0, 200)
for key := range scoreMap {
keys = append(keys, key)
}
for _, key := range keys {
fmt.Println(key, scoreMap[key])
}
map的拷贝
mapp := map[string]int{
"steve": 12000,
"jamie": 15000,
} //map是引用,所以作为函数参数时,map的修改可以被传到函数外
newmapp := mapp //浅拷贝
newmapp["steve"] = 18000 //mapp也会被修改
结构体
结构体的声明
type MyStruct struct { //关键词为type 和 struct
Name string
Age int
}
func (test MyStruct) test() (){
//等效结构体函数、类成员函数
}
func (test *MyStruct) test() (){
//等效结构体函数、类成员函数
//使用指针传入可以对结构体的数据进行修改
}
结构体的实例化与初始化
type test struct { //关键词为type 和 struct
Name string
Age int
}
t1 := test{"Alice", 30}
t2 := test{Name: "Alice"} // Age字段会被自动初始化为0
t3 := new(test) //new返回一个对应类型的指针,所有字段都被初始化为零值
(*t3).Name="123"
var t4 test
t4.Name = "123"
var t5 = &test{}//等效与new
结构体匿名字段
结构体允许其成员字段在申明的时候没有字段名只有字段类型,这种没有名字的字段就称为匿名字段
匿名字段并不是说没有字段名,而是默认会采用类型名作为字段名
结构体要求字段名唯一,因此一个结构体中同种类型的匿名字段只能有一个
type Person struct {
string
int
}
person := Person{
"GGBond",
18,
}
//可以通过匿名字段实现结构体继承
type Animal struct {
name string
}
type Dog struct {
Feet int8
*Animal
}
结构体的JSON序列化与tag
type userInfo struct {
Name string //首字母大写才能使用marshal进行js序列化
Age int `json:"age"` //使用tag实现json序列化该字段时的key
Hobby []string
}
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a) //marshal生成一个byte数组 可以等效成字符串
var b userInfo
err = json.Unmarshal(buf, &b) //反序列化
结构体的拷贝问题
type Person struct {
name string
age int8
dreams []string //由于切片是引用类型,如果涉及到这个元素的赋值,往往需要写一个新的方法来实现深拷贝
}
func (p *Person) SetDreams(dreams []string) {
p.dreams = make([]string, len(dreams))
copy(p.dreams, dreams)
}
拷贝
值类型的数据,默认全部都是深复制,Array、Int、String、Struct、Float,Bool。
引用类型的数据,默认全部都是浅复制,Slice,Map。
深拷贝
对于值类型的数据可以直接使用=进行深拷贝
切片
使用 copy() 函数进行深拷贝
matA := [][]int{
{0, 1, 1, 0},
{0, 1, 1, 1},
{1, 1, 1, 0},
}
matB := make([][]int, len(matA))
for i := range matA {
matB[i] = make([]int, len(matA[i])) // 注意初始化长度
copy(matB[i], matA[i])
}
map
手写函数实现深拷贝
newMap := make(map[string]int)
for k, v := range Map {
newMap[k] = v
}
浅拷贝
不赘述