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

一,字符串

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
    image.png

你可能感兴趣的:(Golang基础数据类型)