Published on

go数据类型初识

Authors
  • avatar
    Name
    noodles
    每个人的花期不同,不必在乎别人比你提前拥有

go数据类型

go语言数据类型主要分为以下的四个大类:

  1. 基础类型(整数,浮点数,负数,布尔值等)
  2. 聚合类型(数组,结构体)
  3. 引用类型(slice,指针,map,函数,通道)
  4. 接口类型

go语言是拥有类型系统的语言,相对于笔者最熟悉的javascript这种动态且无类型的语言来说有着长远的好处.通过类型系统能在编译阶段减少一定的运行时错误.例如在go语言中不同类型值之间必须通过显示转换来进行赋值操作.本文主要从go语言中的基础类型开始,逐步的讲解go语言中几种基本的引用类型.

基础类型

字符串

字符串是不可改变的字节序列.可以通过[i:j]操作符截取对应字符串的子串.由于字符串不可改变的特点,子串和母串共用一端底层内存.

    s := "hello world"
    b := s[6:] // [i:j] 从i开始不包括j 注意越界 b world
    b[0] = 'a' // 错误 

常量

常量是一种表达式,可以在编译的阶段来确定相应的值.在声明常量的时候可以指定类型和值(如果没有指定类型会通过值来推断常量的类型).在连续声明多个常量的时候,主要有以下两种方式:

  1. 在声明枚举值的时候,可以通过iota常量生成器来实现.iota从0开始,逐项加1
  2. 省略赋值语句的一项会复用前一项的表达式和类型
        const (
        a  = iota
        b
        c
        d
        )
        // a b c d 0 1 2 3
        const (
        a = 1
        b
        c = 2
        d
        )
        // a b c d 1 1 2 2

无类型常量

无类型常量(常量字面量)是还没有确定从属类型的常量值.无类型常量相对于同样的有类型的常量有更大的精度.例如0.0相对有浮点数拥有更大的精度.在将无类型常量复制给对应的变量的时候,赋值的变量会转换为无类型常量默认的类型.

i := 0 // int(0) b := 0.0 // float64(0.0)

聚合类型

数组

数组是具有固定长度且拥有零个或者多个相同数据类型元素的序列.由于数组在声明的时候对长度有限制,当存储元素到达数组的容量的时候就需要申请新的内存空间来进行数据的存储.所以在存储数据上一般不会使用数组.数组元素的初始值是该类型的零值.在声明数组的时候需要显示的指定长度和类型.

  1. 声明数组需要有长度的定义和类型定义,可以通过定义长度或者数据数量来确定数组的长度.元素类型和长度相同的数组是可以比较和复制的
  2. 数组元素的初始值为该数组元素类型的初值
  3. 在函数中使用数组指针来完成对原数组的修改
    b := [...]int{1,2,3}  // 通过初始化数组元素的个数决定数组的长度
    a := [3]int{1,2,3}
    a == b // true
    r := [...]int{99: -1} // 定义一个含100元素的数组r 最后一个元素是-1 其余都初始化int类型的零值 0

结构体

结构体是将多个命名变量组合到一起的聚合数据类型.可以通过下面的方式声明一个结构体:

    type Person struct {
	    name string
	    id int
    }

在声明结构体的时候需要注意以下的几点:

  1. 结构体变量的大小写决定变量是否可以导出(可以被其他导出的包读写),
  2. 结构体变量不可以拥有自己本身的结构体类型,可以通过自身结构体类型的指针来实现递归结构

结构体字面量

  1. 可以按照声明的顺序来初始化结构体变量或者指定变量名称来初始化结构体字面量
  2. 可以获取结构体指针来设置结构体的值
        a := Person{ name: "haha" } // 指定变量名声明
        b := Person{ "haha", 20 }
        var copyPerson *Person = &a // 获取结构体指针
        copyPerson.name = "100"

结构体嵌套

在定义结构体的成员的时候,go允许只指定成员的类型来实现成员的声明.通过这种方式定义的结构体成员成为匿名成员.匿名成员的类型必须是一种命名类型或者指向命名类型的指针.匿名成员可以为方便变量提供便捷的操作.

    type Circle struct {
	    x int
	    y int 
	    radius int
    }
    type Wheel struct {	
      Circle
      color string
    }
    wheel := Wheel{Circle{ 10, 10, 19}, "red"}
    // wheel.x = 10

引用类型

slice(切片)

slice是用相同类型元素的可变长度序列.可以基于一个已有的数组来创建这个数组的slice.slice有三个属性:指针,容量,长度.可以在一个数组的基础上产生多个slice,它们共享内存空间.需要注意的是slice可以理解为对原数组的引用,通过对slice的修改是会影响到底层数组的.

声明切片

主要有以下两种方式声明切片:

  1. 通过切片字面量和内置的make函数
  2. slice的操作符[i:j]操作数组或者切片字面量
        var b = make(int[], 3, 5) // make(type[], len, cap) 声明一个长度为3容量为5的切片
        var b = []int{1,2} // 声明一个长度和容量都为2的切片
        var c = []int{ 99: 1 } // 声明一个长度和容量为100的切片,初始化第100的元素为1
        slice := []int{1,2,3,4,5}
        newSlice := slice[1:3]  // 通过切片创建切片
        var num = [10]int{1,2,3,4,5,6,7,8,9,10}
        a := num[1:4] // 操作符[i:j]创建一个新的slice,引用原数组i到j-1个元素.slice的容量是slice起始元素到底层数组最后一个元素之间的个数,切片a只能看到底层数组i以及之后的元素
        len(a) // 3 获取切片的长度
        cap(a) // 9 获取切片的容量
        b := a[:5] // 可以在一个已有的slice上扩充容量,产生新的slice
        len(b) // 4
        cap(b) // 9

操作切片

  1. slice相当于对底层数组的引用,通过操作slice可以修改底层数组
        a := [3]int{1,2,3}  
        b := a[:2]
        b[0] = 100  // a[0]也是100
  1. append函数可以动态的添加元素到slice.append函数会返回一个新的slice
        slice := []int{1,2,3,4,5}
        newSlice := slice[1:2] 
        newSlice = append(newSlice, 10) // newSlice容量足够,修改底层数组返回新的slice. a[2] = 10
        a := slice[1:2]
        b := slice[2:3]
        c = append(a, b...) // 支持批量添加

map

在go中map是对散列表的引用.散列表是无序的键值的结合.可以通过如下的方式创建map:

    var test = make(map[string]int) // 声明map的键值的类型 
    test["name"] = 100  // 赋值
    var person = map[string]int{ "card": 1, id: "2" }  //声明并初始map
    person["card"] // 1

map有以下几点需要特别注意:

  1. 在赋值map类型的值的时候,需要对map进行初始化.初始化的map的值是对应类型的零值.
  2. map是引用类型,在函数间传递的时候会对原值进行修改.