值类型与引用类型
- 值类型:int系列、float系列、bool、string 、数组、结构体struct
- 引用类型:指针、slice切片、map、管道chan, interface,作为参数时,传递的是标头值
引用类型与指针
- 变量在定义时,前面有用标识,那么就是引用类型,如:int。或自带的类型,slice,map,chan等
- 变量存的是一个指针(内存地址),那就是引用类型
int系列
float系列
其他数字类型
var a byte= 'a'
b:=1
fmt.Printf("%c",a+byte(b)) //'b'
数值型的转换
var i int32 = 10
var n int64 =20
//数据类型转换
fmt.Println(int64(i)+n)
var m float32 = 20.3
//数据类型转换
fmt.Println(float32(i)+m)
布尔型
- true
-
字符串
string,须使用双引号进行赋值操作
-
遍历
func main(){
var str string = "hello哈哈"
//遍历汉字,一个中文汉字占3个字节,所有用普通的for len遍历会乱码
str2 := []rune(str)//将字符串转为切片后再进行遍历
//将切片转为字符串,str3=string(str2)
//为什么不用str2 := []byte(str),因为一个汉字的=3个字节,而byte类型只有1个字节,而有4个字节
for i:=0;i<len(str2);i++{
fmt.Printf("%c\n",str2[i])
}
//或者通过for range来遍历
for i ,v :=range str{
fmt.Printf("index=%v,value=%c\n",i,v)
}
}
字符串转数值
func main(){
var s1 string = "a123"
var s2 string = "true"
var s3 string = "100"
var s4 string = "100.123"
var result int64
result,_ = strconv.ParseInt(s1,10,64)
fmt.Printf("类型:%T,值:%v\n",result,result) //转型错误,结果为0
result,_ = strconv.ParseInt(s3,10,64)
fmt.Printf("类型:%T,值:%v\n",result,result)
var result1 bool
result1,_ = strconv.ParseBool(s2)
fmt.Printf("类型:%T,值:%v\n",result1,result1)
var result2 float64
result2,_ = strconv.ParseFloat(s4,64)
fmt.Printf("类型:%T,值:%v\n",result2,result2)
}
数值转字符串
func main(){
num1 :=99
var num2 float64 = 12.345
b :=true
var char byte ='a'
var str string
str= fmt.Sprintf("%d",num1)
fmt.Printf("str :type=%T , value=%q\n",str,str)
str= fmt.Sprintf("%f",num2)
fmt.Printf("str :type=%T , value=%q\n",str,str)
str= fmt.Sprintf("%t",b)
fmt.Printf("str :type=%T , value=%q\n",str,str)
str= fmt.Sprintf("%c",char)
fmt.Printf("str :type=%T , value=%q\n",str,str)
// 通过strconv进行转换
num3 :=99
var num4 float64 = 12.345
b2 :=true
str=strconv.FormatInt(int64(num3),10)
fmt.Printf("str :type=%T , value=%q\n",str,str)
str=strconv.FormatFloat(num4,'f',10,64)
fmt.Printf("str :type=%T , value=%q\n",str,str)
str=strconv.FormatBool(b2)
fmt.Printf("str :type=%T , value=%q\n",str,str)
}
数组
定义
func main() {
//方式一:
var array0 [3] int
fmt.Println(array0) //[0 0 0]
array0[0]=1
array0[1]=2
array0[2]=3
fmt.Println(array0) //[1 2 3]
//方式二:
var array1 [3]int = [3]int{1,2,3}
fmt.Println(array1) //[1 2 3]
//方式三:
var array2 = [3]int{1,2,3}
fmt.Println(array2) //[1 2 3]
//方式四:
var array3 = [...]int{1,2,3}
fmt.Println(array3) //[1 2 3]
//方式五:
var array4 = [...]int{0:1,1:3,2:2}
fmt.Println(array4) //[1 3 2]
//方式六:
//不定长度的数组的长度由元素来决定
array5 :=[...]string{0:"tom",2:"jack",3:"mary"}
fmt.Println(array5,len(array5)) //[tom jack mary] 4
}
//二维数组:
var array [2][3] int//3行4列
var array [...][3] int//注意后面的长度不能省略
array :=[...][3]int{{1,2,3},{4,5,6}}
array[0][1]=2
更高维度:
var array [len][len]...[len] int
遍历
func main() {
array :=[...]string{0:"tom",2:"jack",3:"mary"}
for i:=0;i<len(array);i++{
fmt.Printf("index=%v,value=%q\n",i,array[i])
}
fmt.Println("----------------分割线-----------------")
//用for range遍历
for k,v :=range array{
fmt.Printf("index=%v,value=%q\n",k,v)
}
}
切片
定义
func main() {
var slice []int//这样定义,使用前要先make
slice = make([]int,0,10)
//方式一:定义数组后,通过引用数组来实现
var arr =[...]int{1,2,3,4,5}
//切片是对数组的引用,可以看为是一个动态的数组
slice :=arr[1:4]//含头不含尾
fmt.Println("arr数组的元素是",arr) //[1 2 3 4 5]
fmt.Println("slice切片的元素是",slice) //slice切片的元素是 [2 3 4]
fmt.Println("slice切片的长度是",len(slice)) //slice切片的长度是 3
fmt.Println("slice切片的容量是",cap(slice))//slice切片的容量是 4 ..切片的容量>=长度,
//容量与长度为什么不相等,slice :=arr[1:4],注意容量是按:前的下标开始算,到最后一个元素的。
//方式二:
var slice2 []int =make([]int,10,15)//参数:type,len,cap,cap可以不指定
//方式三:通过这种方式创建,len与cap相等
var slice3 []string = []string{"a","b","c"}
//方式四
slice4 :=new([]string)
}
遍历:与数组一致
注意事项
- arr[:]—-数组全部
- arr[1:]—-除了index=0不要
- arr[:3]—-前3个元素
append
func main() {
var arr =[...]int{1,2,3,4,5}
//切片是对数组的引用,可以看为是一个动态的数组
slice1 :=arr[1:4]//含头不含尾
var slice2 []int =[]int{6,7,8}
slice1=append(slice1,slice2...)
fmt.Println(slice1)
}
copy
func main() {
slice1 := make([]int,10)
var slice2 []int =[]int{1,2,3,4,5}
copy(slice1,slice2)//将slice2拷贝给slice1,按位替换,不会追加,slice1的长度不会改变
fmt.Println(slice1)//[1 2 3 4 5 0 0 0 0 0]
}
//copy是值拷贝
截取
注意:截取是按容量截取的 ```go package mainfunc main() {
arr :=[...]int{1,2,3,4,5}
slice :=arr[:]
fmt.Println(slice)//[1 2 3 4 5]
//切片的截取
newslice :=append(slice[0:2],slice[3:]...)
arr[0]=0//注意newslice任然是对arr的引用
fmt.Println(newslice)//[0 2 4 5]
newslice[0]=6
//切片是对数组的引用,改切片内元素(指针)的值会将原数组也改掉
fmt.Println(arr) //[6 2 3 4 5]
}
import “fmt” func main() { a := make([]int,10,100) a1 := a[9:12] fmt.Println(a1) //[0 0 0] fmt.Println(len(a1)) //3 fmt.Println(cap(a1)) //91 b := make([]int,10) fmt.Println(b[9:12]) //panic: runtime error: slice bounds out of range [:12] with capacity 10 }
<a name="gCLvj"></a>
#### 截取指定容量
```go
func main() {
a := make([]int,10,100)
a1 := a[9:12:12]
fmt.Println(a1) //[0 0 0]
fmt.Println(len(a1)) //3
fmt.Println(cap(a1)) //3
a1[0] = 100
fmt.Println(a) // [0 0 0 0 0 0 0 0 0 100]
}
map
定义
func main() {
**如果先定义var map1 map[int]string,那么使用时,一定要先make
方式一:
//定义map
var map1 map[int]string//其中int为key的类型,string为value的类型
//在使用map前要先make,make的作用是为map分配空间
map1=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充
map1[0]="a"
map1[1]="b"
fmt.Println(map1)//map[0:a 1:b]
方式二:
map2 :=make(map[int]string)
map2[0]="c"
map2[1]="d"
fmt.Println(map2)//map[0:c 1:d]
方式三:
map3 :=map[int]string{
0:"e",
1:"f",
}
fmt.Println(map3)//map[0:e 1:f]
}
这种方式类似上面的方式三
type MyDict map[string]string
func main() {
my := MyDict{"a":"1","b":"2"}
fmt.Println(my)
}
func main() {
my := MyDict{}
my["a"]="1"
my["b"]="2"
}
//map的value为数组,注意数组的长度要固定,否则use of [...] array outside of array literal
Header := map[string][1]string{
"Accept-Encoding": {"gzip, deflate"},
"Accept-Language": {"en-us"},
"Connection": {"keep-alive"},
}
//map的value为切片
Header := map[string][]string{
"Accept-Encoding": {"gzip, deflate"},
"Accept-Language": {"en-us"},
"Connection": {"keep-alive"},
}
//map的value再定义为map
map4 :=make(map[string]map[string]string)
map4["tom"]=make(map[string]string)
map4["tom"]["sex"]="男"
fmt.Println(map4)//map[tom:map[sex:男]]
CUDR
增与改:map1[0]="a"
查:val,ok := map1[0],ok为true(查询成功)或false(查询失败,val为零值,及map中没有该key)
查:val := map1[0],查询失败,val为零值
删:delete(map1,0),如果没有,不会报错
全删:map1 :=make(map[int]string),make一个新空间
遍历
func main() {
map1:=make(map[int]string,10)//type,size。在生成map时,size可以不用指定,会自动扩充
map1[0]="a"
map1[1]="b"
map1[3]="c"
for k,v :=range map1{
fmt.Printf("key:%v,value:%v\n",k,v)
}
for k:=range map1{ // 这样只遍历map1的所有key
fmt.Printf("key:%v\n",k)
}
}
key:0,value:a
key:1,value:b
key:3,value:c
func main() {
map4 :=make(map[string]map[string]string)
map4["tom"]=make(map[string]string)
map4["tom"]["sex"]="男"
map4["tom"]["age"]="20"
map4["mary"]=make(map[string]string)
map4["mary"]["sex"]="女"
map4["mary"]["age"]="18"
for k,v :=range map4{
fmt.Printf("第一层key为%v\n",k)
for i,m :=range v{
fmt.Printf("key:%v,value:%v\n",i,m)
}
}
}
第一层key为tom
key:age,value:20
key:sex,value:男
第一层key为mary
key:sex,value:女
key:age,value:18
map切片
func main() {
//声明map切片
student :=make([]map[string]string,1)
student[0]= make(map[string]string)
student[0]["name"]="tom"
student[0]["sex"]="男"
newstudent := make(map[string]string)
newstudent["name"]="mary"
newstudent["sex"]="女"
student = append(student,newstudent)
fmt.Println(student)//[map[name:tom sex:男] map[name:mary sex:女]]
}
深拷贝
最简单的方法是用json unmarshal,变成字符串,然后再用 json marshal生成新的map。这种方法对结构体也适用。
如果是map[string]interface{}和[]interface{}的组合,用代码递归也很简单:
func DeepCopy(value interface{}) interface{} {
if valueMap, ok := value.(map[string]interface{}); ok {
newMap := make(map[string]interface{})
for k, v := range valueMap {
newMap[k] = DeepCopy(v)
}
return newMap
} else if valueSlice, ok := value.([]interface{}); ok {
newSlice := make([]interface{}, len(valueSlice))
for k, v := range valueSlice {
newSlice[k] = DeepCopy(v)
}
return newSlice
}
return value
}
零值
var b bool // false
var s string // ""
var f float系列 //0
var i int系列 //0
var a [2]int //[0 0],由于数组在定义时必须制定长度,所以它的零值为[0 0 ...]
// 以下六种类型零值常量都是nil
var a *int
var a []int,注意这个是切片不是数组
var a map[string] int
var a chan int
var a func(string) int
var a error // error是接口