golang-基础知识(array, slice, map)

1. array

array就是数组,我们可以通过如下方式定义一个数组并对数组中的元素进行赋值

var arr [n]type  // 定义一个大小为n,类型为type的数组
arr[0] = xx // 对数组中的元素进行赋值

其中[n]type中,n表示数组的长度,type表示数组的类型,由于长度也是数组类型的一部分,所以[3]int和[4]int是两种不同的类型,数组也就不能改变长度

简单例子:

package main

import (
	"fmt"
)

func main() {
	var arr [4]int
	arr[0] = 1
	fmt.Print(arr)
}

这里我们定义了一个长度为4的Int数组,并将数组中的第一个元素赋值为1,最后打印出该数组

可以看到,除了第一个元素外,其它三个元素都使用了默认值0

同样的,我们可以使用 := 来简化数组的声明,例子如下

package main

import (
	"fmt"
)

func main() {
	arr1 := [3]int{1, 2, 3}         // 声明了一个长度为3的int数组
	arr2 := [10]int{1, 2, 3}        // 声明了一个长度为10的int数组,其中前三个元素初始化为1、2、3,其它默认为0
	arr3 := [...]int{1, 2, 3, 4, 5} // 可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度
	fmt.Println(arr1)
	fmt.Println(arr2)
	fmt.Println(arr3)

	// 声明了一个二维数组,该数组以两个数组作为元素,其中每个数组中又有4个int类型的元素
	arr4 := [2][4]int{[4]int{3, 3, 3, 3}, [4]int{4, 4, 4, 4}}
	fmt.Println(arr4)

	// 上面的声明可以简化,直接忽略内部的类型
	arr5 := [2][4]int{{1, 1, 1, 1}, {2, 2, 2, 2}}
	fmt.Println(arr5)
}

我们可以通过以上方便的声明不同长度,不同类型的数组(包括二维数组),运行结果如下:

2. slice

很多时候,我们并不知道具体要用多大的数组,无法确定数组的长度,因此就有了slice(切片)的概念,slice可以理解成一个动态的数组,但它又不是一个真正意义上的动态数组,而是一个引用类型,总是指向一个array,它的声明和array类似,只是省略了长度

var sli []int

slice可以定义一个空slice并逐渐追加元素或者,从一个已经定义好的数组或者slice中再次声明(通过array[i:j]获取,包括从i到j-1元素,其中i和j都可以省略,这里用法和python一致),例子如下:

package main

import (
	"fmt"
)

func main() {
	// 定义一个空slice并逐渐追加元素
	var aSlice []int
	aSlice = append(aSlice, 0)
	fmt.Println(aSlice)

	// 从一个已经定义好的数组或者slice中再次声明
	byteArray := [10]byte{'a', 'b', 'c'}
	fmt.Println(byteArray)
	byteS1 := byteArray[1:5]
	fmt.Println(byteS1)
	byteS2 := byteS1[1:3]
	fmt.Println(byteS2)

}

运行结果如下:

由于slice是引用类型,当同时有多个slice指向同一个数组时,其中一个slice的修改会影响到其它的slice,比如,在上面的例子中增加如下代码

byteS2[0] = 10
fmt.Println("afte modify")
fmt.Println(byteS1)
fmt.Println(byteS2)

输出结果后,我们发现,两个slice的值都发生了变化

slice有一些有用的内置函数

len返回切片的长度
append往切片中追加元素,存在多个切片指向同一个数组时,更新一个切片可能会更新其它切片
cap返回切片的最大容量
copy从src切片复制元素到到目标dst,返回复制元素的个数(为src和dst切片长度的最小值)

使用这些内置函数的例子如下:

package main

import (
	"fmt"
)

func main() {
	// 从一个已经定义好的数组或者slice中再次声明
	byteArray := [10]byte{'a', 'b', 'c'}
	fmt.Println(byteArray)
	byteS1 := byteArray[1:5]
	fmt.Println(byteS1)
	byteS2 := []byte{'v', 'w'}
	num := copy(byteS2, byteS1)
	fmt.Printf("byteS2 = %v, num = %v\n", byteS2, num)

	byteS2 = append(byteS2, 'f')
	fmt.Println(byteS2)
	fmt.Printf("the len of byteS2 = %v, and the cap of byteS2 = %v\n", len(byteS2), cap(byteS2))
}

在代码中,我们定义了两个切片,然后执行拷贝,添加,计算长度,容量操作,结果如下:

3. map

map,字典,键值对的形式,格式为map[keyType]valueType,map的读取和设置和slice类似,只不过slice的下标只能是int类型,而map可以是多种类型,可以是string, int, 或者其它定义了==与!=操作的类型

一个简单例子如下:

package main

import "fmt"

func main() {
	var m map[string]int
	m = make(map[string]int)
	m["a"] = 1
	m["b"] = 2
	fmt.Printf("m[a] = %v, m[b] = %v", m["a"], m["b"])
}

以上代码定义了一个string到int的map,这种定义方式需要在使用之前使用make进行初始化,初始化后,给map中元素赋值,赋值之后并打印出相应的元素

使用map的时候需要注意以下几点

  • map是无序的,不能通过index获取,只能通过key获取
  • map的长度不固定,这点和slice一致,也就是说,map也是引用类型(两个map指向同一个底层,一个map的改变也会影响到另一个map)
  • 内置函数len同样适用于map,返回的是map的key的个数
  • map的值可以很方便修改,map[key] = newValue即可
  • map和其它基本类型不同,它不是线程安全的,如果存在多个go-routine读取时,需要使用mutex lock机制

除了以上几点,map也存在简单初始化,判断key是否存在,以及删除key的操作,例子如下:

package main

import "fmt"

func main() {
	m := map[string]string{
		"myname":  "lilei",
		"teacher": "wang",
	}
	value, ok := m["myname"]
	if !ok {
		fmt.Println("key history not exists")
	} else {
		fmt.Printf("the value of key myname is %v\n", value)
	}
	delete(m, "myname")
	fmt.Println(m)
}

这里初始化了一个map,查询map中的值并删除,结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值