Golang 基础语法-高级数据类型(3)

前端之家收集整理的这篇文章主要介绍了Golang 基础语法-高级数据类型(3)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Golang 基础语法-高级数据类型(3)

本文主要介绍 golang 内置数据类型的 array,slice,map。这几种数据类型在日常使用中是非常常见的。

array

定义语法如下:
var arr [n]type
其中 arr 是数组变量的名称(标识符),[n]type 表示这个数组是类型为 type 且长度为 n 的数组(type 可以是任何基本类型,也可以是任何自定义类型)
//实例演示
var arr [10]int //定义一个长度为10的 int 类型的数组
arr[0] = 42 //array 数组下标是从0开始的,给数组第一个元素赋值42
arr[1] = 13//给数组第二个元素赋值13
//打印数组第一个元素
fmt.Printf("数组 arr 第一个元素是 %d\n",arr[0])
//打印数组最后一个元素,arr[9]因为没有初始化,输出 int 类型的零值 0
fmt.Printf("数组 arr 最后一个元素是 %d\n",arr[9])
定义数组的时候,可以把[n]type 看做一个完整的类型,举个例子,[3]int 和 [4]int 可以认为是不同的数据类型,数组的长度也是不可修改

当把一个 array类型的数据作为函数参数传递的时候,传递的是 array 的copy(拷贝值)而不是引用

/**
 * 数组是值传递而非引用传递
 */
func test(arr [4]int) int {
    var sum int
    for i,v := range arr {
        sum = sum + v
        arr[i] = sum
    }
    //打印结果是[1 3 7 12]
    fmt.Printf("%+v\n",arr)
    return sum
}
func main() {
    arr := [4]int{1,2,4,5}
    //打印结果 12
    fmt.Printf("%d\n",test(arr))
    //打印结果[1 2 4 5],把 arr 传递给 test函数,且函数修改了数组,没有影响原数组,证明数组在函数参数中是传递 copy而不是引用
    fmt.Printf("%v\n",arr)
}
//快捷方式定义数组
arr := [3]int{1,3}
//使用 ...替代长度让编译器自动计算数组的长度
arr1 := [...]int{3,5,5}
//二维数组
darr :=[2][3]int{[3]int{1,3},[3]int{33,33,33}}
darr1 := [2][3]int{{2,3,4},{1,4}}

slice(切片或者变长数组)

数组在一开始的时候,就要知道它的长度,然而很多时候我们并不能确定数组的大小,需要一种 "动态数组".在 golang 中 slice 为我们提供了这种可能。

slice 的定义和 array 非常相近,区别就是不用设置 n
语法 var slice[]int

说明:以上语法定义了一个 int 类型的 slice,

//实例说明
//定义一个byte 类型的 slice,注意 byte 是uint8的别名,byte类型的 slice中,如果元素赋值为汉字超出 uint8的范围就会报错
slice := []byte{'a','b','c'}
slice 可以从已经存在的数组(array)或者切片(slice)重新定义一个切片,语法格式为[i:j],i 是开始的索引,j 是结束的索引,但是最终的 slice 不包含 j 这个元素
//实例演示
var ar = [10]byte{'a','c','d','e','f','g','h','i','j'}
var a,b []byte
//变量a 实际上的内容为 c,d,e 且 a 和 ar 共用底层数据
a = ar[2:5]
//变量 b 实际上的内容为 d,e 且 b 和 ar 共用底层数据
b = ar[3:5]
//思考如下结果是什么?
ar[4] = 'x'
fmt.Printf("%c\n",ar[4])//显然是 x
fmt.Printf("%c\n",a[2])//a[2]实际上指向的是 ar[4],结果是 x
fmt.Printf("%c\n",b[1])//b[1]实际上指向的是 ar[4],结果是 x
ar[:n] 等价于 ar[0:n]
ar[n:] 等价于 ar[n:len(ar)]
ar[:] 等价于 ar[0:len(ar)]
//实例演示
var arr = [10]byte{'a','j'}

var aSlice,bSlie []byte
aSlice = arr[:3] // a b c
aSlice = arr[5:] //f g h i j
aSlice = arr[:] // a b c d e f g h i j
aSlice = arr[3:7] // d e f g,长度 len=4,容量 cap=10-3
bSlice = aSlice[1:3] // e f

slice 是引用类型,因此任何改变都会影响指向同一个 slice的其他 slice 或 数组。

slice 类似于结构体,包涵了下面三个部分

  • 一个指针:指向 slice 的起始地址
  • slice 的长度 int 类型
  • slice 的容量 int 类型

有一些内置函数可以操作 slice

  • len 获取 slice的长度
  • cap 获取 slice 的最大容量
  • append 追加一个或者多个 slice 到slice
  • copy 复制一个 slice 的所有元素到另外一个 slice,返回复制元素的个数

map

Map是一种键值对数据结构,类似python 中的字典。定义语法如下:

map[keyType]valueType

slice 中索引只能是 int,在 map 中 key可以是 int string 等任何你想要的类型

实例演示如下

//使用 string 类型的 key,int类型的 value,可以使用 make 初始化
var numbers map[string]int
//定义并且使用 make 初始化
numbers := make(map[string]int)
//初始化后可以赋值
numbers["one"] = 1
numbers["two"] = 2
numbers["three"] = 3
//获取 map 某个 key 的 value
fmt.Println(numbers["three"])

map 需要注意

  • map是无序的,每次打印显示的结果可能都是不一样的,只能使用 key 获取 value
  • map 没有固定的长度,它是一种引用型变量
  • len函数可以用于获取 map 的长度,返回 map 有多少个 key
  • 通过 key改变 map 的 value 非常容易 只需要 使用类似m["k"] = 1的语法修改
//定义并且初始化 map
rating := map[string]float32 {"C":5,"Go":4.5,"PHP":100}
javaRating,ok := rating["Java"]
if ok {
    //do something
}else{
    //do something
}
//删除 map 中的某个键值对
delete(rating,"C")

m := make(map[string]string)
m["hello"] = "world"
m1 := m
m1["hello"] = "girl" //m["hello"]的值也是 girl,因为底层指向数据一致

make 和 new 的区别

make 是 go 内置的一个方法,用于为 map,slice,channel 等内置类型分配内存,new可以为所有类型分配
new(T)给 T 分配零值内存,返回零值的内存地址,其实就是 *T,更详细的说,就是返回一个指针,指针指向的是 T 的零值

new 返回指针

make 主要用于 slice map channel,返回初始化后的 T。原因在于 map slice channel底层的数据必须在初始化后才能指向他们。举个例子,slice 包涵了一个指针,这个指针实际指向的是另外一个结构(包涵指针 长度 容量),在这些数据初始化之前 slice 是 nil,因此 slice,map,channel使用 make为他们底层的数据结构赋值合适的初始值

make 返回 非零值

猜你在找的Go相关文章