Golang基础数据类型

本节介绍Golang的基本数据类型,字符串,整型,浮点型,数组,切片 | 类型 | 长度(字节 byte) | 默认值 | 说明 | | ---- | ---- | ---- | ---- | | bool | 1 | false | | | byte | 1 | 0 | uint8 | | rune | 4 | 0 | Unicode Code Point, int32| | int, uint | 8 | 0 | 32 或 64 位 | | int8, uint8 | 1 | 0 | -128 ~ 127, 0 ~ 255,byte是uint8 的别名 | |int8, uint8 |1 | 0 | -128 ~ 127, 0 ~ 255,byte是uint8 的别名 | |int16, uint16 | 2 |0 | -32768 ~ 32767, 0 ~ 65535 | |int32, uint32 |4 | 0 |-21亿~ 21亿, 0 ~ 42亿,rune是int32 的别名 | |int64, uint64 | 8 |0 | | |float32 |4 | 0.0 | | |float64 |8 |0.0 | | | complex64 | 8 | | | | complex128 16 | | | | uintptr | 4或8 | | 以存储指针的 uint32 或 uint64 整数 | | array | | | 值类型 | | struct | | | 值类型 | | string | | "" | UTF-8 字符串 | | slice | | nil | 引用类型 | | map | | nil | 引用类型 | | channel | | nil | 引用类型 | | interface | | nil | 接口 | | function | | nil | 函数 | 注意项: - float32大约可以提供小数点后6位的精度,作为对比,float64可以提供小数点后15位的精度。通常情况应该优先选择float64,因此float32的精确度较低,在累积计算时误差扩散很快,而且float32能精确表达的最小正整数并不大,因为浮点数和整数的底层解释方式完全不同 [https://studygolang.com/articles/6429](https://studygolang.com/articles/6429) ### 一,字符串 ##### 1,字符串长度与拼接 ``` var name = "小明!" say := "Hello,This is my City" fmt.Println(len(name)) // 9 一个汉字 占3个字节 fmt.Println(len(say)) // 21 英文字母和空格,都占一个字节 fmt.Println(name + " " + say) // + 号可用于字符串拼接 // 小明! Hello,This is my City fmt.Printf("%v %v \n",name,say) // 小明! Hello,This is my City ``` ##### 2,字符串分割 ``` arr := strings.Split(say," ") //返回一个切片:[]string fmt.Println(arr) // [Hello,This is my City] fmt.Println(len(arr)) // 4 fmt.Println(cap(arr)) // 4 ``` ##### 3,判断是否包含 ``` exist := strings.Contains(name,"小") fmt.Println(exist) // true ``` ##### 4,判断子串出现位置,如果没有出现,返回 -1 ``` idx := strings.Index(say,"i") //第一个出现的位置 fmt.Println(idx) // 8 ,是从 0 开始的 fmt.Println(strings.LastIndex(say,"i")) // 18 ``` ##### 5,切片合并成字符串 ``` fruits := []string{"苹果","橘子","香蕉"} fmt.Println(strings.Join(fruits,",")) // 苹果,橘子,香蕉 fmt.Println(reflect.TypeOf(strings.Join(fruits,","))) // string ``` ##### 6,字符串转整形(有两个返回值,处理err) ``` var strNum1 = "123" var strNum2 = "123.456" num1,err := strconv.Atoi(strNum1) if err != nil { num1 = 0 } fmt.Println(num1) // 123 num2,err2 := strconv.Atoi(strNum2) if err2 != nil { fmt.Println(err2) //strconv.Atoi: parsing "123.456": invalid syntax num2 = 0 //被触发,同理,strNum2 = "123.0"也会被触发 } fmt.Println(num2) // 0 ``` ##### 7,字符串转浮点型: ``` num3,err3 := strconv.ParseFloat(strNum1,32) if err3 != nil { num3 = 0 } fmt.Println(num3) // 123 num4,err4 := strconv.ParseFloat(strNum2,64) if err4 != nil { num4 = 0 } fmt.Println(num4) //123.456 ``` ### 二,整形与浮点型 ##### 1,数字类型之间互相转换: ``` var num6 int64 = 100 var num7 float64 = 123.356 fmt.Println(reflect.TypeOf( int32(num6) )) // int32 fmt.Println(reflect.TypeOf( float64(num6) )) //float64 ``` 同理,还有`int8() , int16() , int64() , float32()` 等函数 ##### 2,整形转字符串: ``` str1 := strconv.Itoa( int(num6) ) //这个函数只能传入int类型的,不能传入int64等其他整型的,淦 fmt.Println(str1) // 100 ``` ##### 3,浮点型转字符串: ``` str2 := strconv.FormatFloat(num7,'f',2,64) fmt.Println(str2) // 123.36 ``` ### 三,数组 ``` func main() { // 1,声明:元素类型 元素个数 var strList [5]string fmt.Println(strList) //[ ] 声明一个数组后会自动设置其默认值 var numList [5]int fmt.Println(numList) //[0 0 0 0 0] //2,声明,并初始化 var list3 = [5]int{1,2,3} fmt.Println(list3) //[1 2 3 0 0] //3,声明,初始化,自动识别数组个数: var list4 = [...]int{1,2,3,4} fmt.Println(list4) //[1 2 3 4] fmt.Println(cap(list4)) //[1 2 3 4] fmt.Println(len(list4)) //[1 2 3 4] //4,函数传参与遍历 getList(list3) } func getList(list [5]int){ //第一种遍历: for i := 0; i < len(list); i++ { fmt.Println(list[i]); // 1 2 3 0 0 //通过下标访问元素 } //第二种遍历: for key, value := range list { fmt.Printf("%v => %v \n",key,value) // 0 => 1 } } ``` 注意事项: - 1,数组:是同一种数据类型的固定长度的序列。 - 2,长度是数组类型的一部分,因此,var a[5] int和var a[10]int是不同的类型。`fmt.Println(reflect.TypeOf(list3)) //[5]int` - 3,访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic - 6,数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。 - 7,支持 "=="、"!=" 操作符,因为内存总是被初始化过的。 - 8,指针数组 [n]*T,数组指针 *[n]T。 ``` var list5 = [3]int{1,2,3} var list6 = [3]int{1,2,3} fmt.Println( list5 == list6 ) //true var list7 = [3]int{1,2,4} fmt.Println( list6 == list7 ) //false ``` 1,多维数组: ``` var list8 = [2][3]int{ {1,2,3}, {7,8,9}, } fmt.Println(list8) // [[1 2 3] [7 8 9]] ``` ### 四,切片 需要说明,slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。 1. 切片:切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。 2. 切片的长度可以改变,因此,切片是一个可变的数组。 3. 切片遍历方式和数组一样,可以用len()求长度。表示可用元素数量,读写操作不能超过该限制。 4. cap可以求出slice最大扩张容量,不能超出数组限制。0 <= len(slice) <= len(array),其中array是slice引用的数组。 5. 切片的定义:var 变量名 []类型,比如 var str []string var arr []int。 6. 空切片等于nil :` fmt.Println(slice1 == nil) //true`。 如果 slice == nil,那么 len、cap 结果都等于 0。 ##### 1,切片的各种定义: ``` //切片的声明:1,声明一个不定长数组, var slice1 []int fmt.Println(slice1) // [] fmt.Println(slice1 == nil) //true slice1 = append(slice1,1) //增加一个元素 fmt.Println(slice1) // [1] //切片的声明:2,通过make函数创建 var slice2 []int = make([]int,2)// []数据类型 ,长度 fmt.Println(slice2) //slice1[2] = 4 //注意:不可以直接为不存在的键赋值,需要通过append增加后才能 set,get slice2 = append(slice2,4) fmt.Println(slice2[2]) //4 //通过截取数组,来生成切片:slice = num[startIndex:endIndex] 如果不填则为默认值:num[0 : max] var num = [5]int{1,3,5,7,9} var slice3 = num[:] fmt.Println(slice3) //[1 3 5 7 9] slice3 = num[1:] fmt.Println(slice3) //[3 5 7 9] //可以看到,包含startIndex slice3 = num[:2] fmt.Println(slice3) //[1 3] //可以看到,不包含endIndex ``` ##### 2,切片的长度 - len()函数可以获取切片当前长度,cap()函数可以获取切片的最大长度 ``` var x []int = make([]int,3,5) fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) //len=3 cap=5 slice=[0 0 0] x = append(x,1) x = append(x,2) x = append(x,3) x = append(x,4) x = append(x,5) x = append(x,6) x = append(x,1) //经过试验可以发现,make定下的最大长度cap = 5,其实是可以增加到6,7个元素的,并不是最大只能存5个 x = append(x,1) //当切片长度超过cap时,cap会增长一倍,就是用自己乘以2,直到放得下所增加的元素 fmt.Println(x) fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x) //len=11 cap=20 slice=[0 0 0 1 2 3 4 5 6 1 1] ``` ##### 3,遍历 切片的遍历与上面数组相同 语言范围Range: - 1,语法: key,value := range + 变量 : 该用法返回变量中的 元素的 索引和值,如果是集合,则返回key - value 对 - 2,range + 变量,他有两个返回值,如果某一个返回值你不需要用到,用 _ 接收 ##### 4,切片的本质 ``` func main() { slice := []int{1, 2, 3, 4, 5} fmt.Printf("切片:%v\n", slice) //切片:[1 2 3 4 5] fmt.Printf("slice pointer is : %p \n",slice) // slice pointer is : 0xc00000a2d0 fmt.Printf("&slice pointer is : %p \n",&slice) // &slice pointer is : 0xc0000044a0 changeSlice1(slice) fmt.Printf("切片:%v\n", slice) //切片:[1 2 10 4 5] fmt.Printf("slice pointer is : %p \n",slice) // slice pointer is : 0xc00000a2d0 fmt.Printf("&slice pointer is : %p \n",&slice) // &slice pointer is : 0xc0000044a0 } func changeSlice1(slice []int) { slice[2] = 10 fmt.Printf("切片:%v\n", slice) //切片:[1 2 10 4 5] fmt.Printf("slice pointer is : %p \n",slice) // slice pointer is : 0xc00000a2d0 fmt.Printf("&slice pointer is : %p \n",&slice) // &slice pointer is : 0xc000004520 指针已经不同,可见发生了拷贝 } ``` - 1,由上面的代码中可以看到,打印传入函数的slice(值),一直都是 0xc00000a2d0 ,但是这个值的指针:&slice,是不一样了的,证明值经过了拷贝。那为什么函数里面的切片的改变,导致了调用处的切片也一并改变了呢?因为切片的本质就是一个由:保存该切片元素的数组的指针(也就是上面打印出来的0xc00000a2d0 ) + len + cap 的结构体组成,它传了这个值(0xc00000a2d0)进去,进而函数changeSlice1()对这个值所指向的真实数组做处理,从而,导致了调用出的切片的值也发送了改变。 - 2,Go的参数传递都是值传递,参考资料:https://blog.csdn.net/chen_peng7/article/details/89247047 [![](http://static.tscgo.cn/FqAiFP5J9emjHZaD6xFzMDWmljpV )](http://static.tscgo.cn/FqAiFP5J9emjHZaD6xFzMDWmljpV ) 至此,golang的基本数据类型暂时分享到这里。

评论

  1. #1

    柠栀 2021-12-01 08:49:53
    深夜还在分享啊 辛苦了