Go语言复合类型

Go语言也支持以下这些复合类型:

  • 指针(pointer)
  • 数组(array)
  • 切片(slice)
  • 字典(map)
  • 通道(chan)
  • 结构体(struct)
  • 接口(interface)

1. 数组

  • 数组中包含的每个数据被称为数组元素(element),一个数组包含的元素被称为数组的长度。
  • 以下为一些常规的数组声明方法:
[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 } // 复杂类型数组
[1000]*float64 // 指针数组
[3][5]int // 二维数组
[2][2][2]float64 // 等同于[2]([2]([2]float64))
  • 在Go语言中,数组长度在定义后就不可更改,在声明时长度可以为一个常量或者一个常量
    表达式(常量表达式是指在编译期即可计算结果的表达式)。
  • 数组的长度是该数组类型的一个内置常量,可以用Go语言的内置函数len()来获取。下
  • 元素访问
// 使用数组下标来访问数组中的元素。
for i := 0; i < len(array); i++ {
    fmt.Println("Element", i, "of array is", array[i])
}
// Go语言还提供了一个关键字range,用于便捷地遍历容器中的元素。
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
// range具有两个返回值,第一个返回值是元素的数组下标,第二
// 个返回值是元素的值。
  • 值类型

需要特别注意的是,在Go语言中数组是一个值类型(value type)所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。如果将数组作为函数的参数类型,则在函数调用时该
参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所
传入数组的一个副本。

2. 数组切片slice

  • 数组的特点:数组的长度在定义之后无法再次修改;
  • 数组是值类型,每次传递都将产生一份副本。

    创建数组切片

  • 基于数组

    数组切片可以基于一个已存在的数组创建。数组切片可以只使用数组的一部分元素或者整个
    数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片。代码清单2-1演示了如何基
    于一个数组的前5个元素创建一个数组切片。
package main
import "fmt"

func main() {
    //先定义一个数组
    var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    //基于数组创建一个数组切片
    var mySlice []int = myArray[:5]

    fmt.Println("Elements of myArray:")
    for _, v := range myArray {
        fmt.Print(v, " ")
    }

    fmt.Println("\nElements of myArray:")

    for _, v := range mySlice {
        fmt.Print(v, " ")
    }

    fmt.Println()

}
//main()不用显调用

/*运行结果为:
Elements of myArray:
1 2 3 4 5 6 7 8 9 10
Elements of mySlice:
1 2 3 4 5*/
  • 直接创建

    Go语言提供的内置函数make()可以用于灵活地创建数组切片。
//创建一个初始元素个数为5的数组切片,元素初始值为0:
mySlice1 := make([]int, 5)
//创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:
mySlice2 := make([]int, 5, 10)
//直接创建并初始化包含5个元素的数组切片:
mySlice3 := []int{1, 2, 3, 4, 5}

元素遍历

操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len()
函数获取元素个数,并支持使用range关键字来快速遍历所有元素。

动态增减元素

可动态增减元素是数组切片比数组更为强大的功能。与数组相比,数组切片多了一个存储能
力(capacity)的概念,即元素个数和分配的空间可以是两个不同的值。合理地设置存储能力的
值,可以大幅降低数组切片内部重新分配内存和搬送内存块的频率,从而大大提高程序性能。

  • 数组切片支持Go语言内置的cap()函数和len()函数
  • cap()函数返回的是数组切片分配的空间大小
  • len()函数返回的是数组切片中当前所存储的元素个数。

append()函数

从尾端给mySlice加上3个元素,从而生成一个新的数组切片:

mySlice = append(mySlice, 1, 2, 3)

函数append()的第二个参数其实是一个不定参数,我们可以按自己需求添加若干个元素,

甚至直接将一个数组切片追加到另一个数组切片的末尾

mySlice = append(mySlice, mySlice2...)

需要注意的是,我们在第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省
略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的
元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相
当于把mySlice2包含的所有元素打散后传入。

基于数组切片创建数组切片

oldSlice := []int{1, 2, 3, 4, 5}

newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片

有意思的是,选择的oldSlicef元素范围甚至可以超过所包含的元素个数,比如newSlice
可以基于oldSlice的前6个元素创建,虽然oldSlice只包含5个元素。只要这个选择的范围不超
过oldSlice存储能力(即cap()返回的值),那么这个创建程序就是合法的。newSlice中超出
oldSlice元素的部分都会填上0。

内容复制

数组切片支持Go语言的另一个内置函数copy(),用于将内容从一个数组切片复制到另一个
数组切片。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行
复制。下面的示例展示了copy()函数的行为:

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

map

package main
import "fmt"
// PersonInfo是一个包含个人详细信息的类型
type PersonInfo struct {
    ID string
    Name string
    Address string
}
func main() {
    var personDB map[string] PersonInfo
    personDB = make(map[string] PersonInfo)
    // 往这个map里插入几条数据
    personDB["12345"] = PersonInfo{"12345", "Tom", "Room 203,..."}
    personDB["1"] = PersonInfo{"1", "Jack", "Room 101,..."}
    // 从这个map查找键为"1234"的信息
    person, ok := personDB["1234"]
    // ok是一个返回的bool型,返回true表示找到了对应的数据
    if ok {
        fmt.Println("Found person", person.Name, "with ID 1234.")
    } else {
        fmt.Println("Did not find person with ID 1234.")
    }
}

这里关于personDB先声明,再用make初始化(或称为创建)的理解

在Go中变量要先声明类型才能被赋值,所以,personDB在被声明后才能接收make()返回的map对象

使用自动推导,可以将两条语句缩减成一句:personDB := make(map[string] PersonInfo)

这里用到了make, what

创建切片、映射、或通道的对象需要用make()

func make

func make(Type, size IntegerType) Type
//示例
myMap = make(map[string] PersonInfo, 100)

内建函数make分配并初始化一个类型为切片、映射、或通道的对象。其第一个实参为类型,而非值。make的返回类型与其参数相同,而非指向它的指针。其具体结果取决于具体的类型:

切片:size指定了其长度。该切片的容量等于其长度。切片支持第二个整数实参可用来指定不同的容量;
    它必须不小于其长度,因此 make([]int, 0, 10) 会分配一个长度为0,容量为10的切片。
映射:初始分配的创建取决于size,但产生的映射长度为0。size可以省略,这种情况下就会分配一个
    小的起始大小。
通道:通道的缓存根据指定的缓存容量初始化。若 size为零或被省略,该信道即为无缓存的。

func new

func new(Type) *Type

内建函数new分配内存。其第一个实参为类型,而非值。其返回值为指向该类型的新分配的零值的指针

Go中的变量是什么?

变量只是给程序可以操作的存储区域的名字,Go语言中的每一个变量都拥有一个特有的类型,类型决定了变量的内存的大小和布局,可以存储在存储器内的值的范围,以及可以应用于该变量的一组操作。

* 值类型和引用类型

  • 所有像int,float,bool,string这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存的值;
  • 当使用等号”=“ 将一个变量的值赋给另一个变量时,如:j=i,实际上是在内存中将i的值进行拷贝;
  • &可以获取到变量的地址。值类型的变量的值存在栈中。
  • *值类型的变量,是内存地址的别名,地址标识的内存空间放着

  • 更复杂的是数据通常会需要使用多个字,这些数据一般使用引用类型保存。
  • 一个引用类型的变量存储实际值所在的地址,或者是内存地址中第一个字所在的位置。
  • r1 | address1 ---> address1 | value
  • 当使用赋值语句 r2 = r1 时,只有引用(地址)被复制。
  • r1 | address1 ---> address1 | value
  • r2 | address1
  • &可以获取到变量的地址。

用操作符 := 可以高效地创建一个新的变量,称之为初始化声明。

这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。

字典操作

  1. 赋值
    myMap["1234"] = PersonInfo{"1", "Jack", "Room 101,..."}
  2. 删除
    delete(myMap, "1234")
    上面的代码将从myMap中删除键为“1234”的键值对。如果“1234”这个键不存在,那么这个调
    用将什么都不发生,也不会有什么副作用。但是如果传入的map变量的值是nil,该调用将导致
    程序抛出异常(panic)
  3. 查找
value, ok := myMap["1234"]
if ok { // 找到了
// 处理找到的value
}

判断是否成功找到特定的键,不需要检查取到的值是否为nil,只需查看第二个返回值ok,
这让表意清晰很多。

转载于:https://www.cnblogs.com/ravener/p/9858429.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值