Go - 数据结构

本文深入探讨了Go语言中的数据结构,包括Array的初始化、访问与赋值,Slice的定义、引用传递及内存隐患,String的特性以及Map的初始化、长度获取和Key操作。重点解析了Array与Slice的区别,强调了Slice的引用传递性质,以及Map的引用传递导致的数据错误和解决方案。最后总结了不同数据结构在函数参数传递中的行为。
摘要由CSDN通过智能技术生成

一、Array

数组和切片是 Go 语言中最常见的数据结构。

数组是由相同类型的元素的集合的数据结构,被分配一块的连续的内存用来保存数据,且可以通过其中存储的索引进行快速访问其存储地址。

1-1 Array 的初始化

Array 是定长的,一旦初始化后,无法改变其长度大小;而 Slice 是不定长的Array。

array 的初始化有两种方式:1、显式指定长度 2、使用可变参数,由语言推断长度

arr1 := [3]int{
   1, 2, 3}
arr2 := [...]int{
   1, 2, 3}
arr3 := [10]int{
   } // 10 长度,元素为初始值的数组

两种初始化的方式,主要体现在编译器创建对应 array 的位置。

显式指定长度:编译器会在类型检查阶段就能提出变量的类型

可变参数推断长度:声明时,默认数组的大小上限为 -1,-1 作为一个占位符。编译器会在后续编译过程中将使用可变参数的 Array 定义为 DDDArray,使用遍历元素的方式计算数组中元素的数量。

1-1-1 Array 的初始化可指定索引和对应值

import (
    "fmt"
)

func main(){
   
    arrayA := [...]int{
   0:1, 2:1, 3:4}
    fmt.Println(arrayA) // [1 0 1 4]
  	fmt.Println(len(arrayA)) // 4
}

技巧:可通过仅定义 array 最后一个元素的值,来初始化长度。

package main
import (
	"fmt"
)

func main(){
   
	arrayA := [...]int{
   9:1}
  // or,arrayA := [10]int{} 
	fmt.Println(arrayA) //[0 0 0 0 0 0 0 0 0 1]
	fmt.Println(len(arrayA)) // 10
}

1-2 Array 的访问和赋值

1-2-1 range 循环 Array 返回索引和值

package main
import "fmt"
func main() {
     
    x := []string{
   "a","b","c"}
    for _, v := range x {
   
        fmt.Println(v) //prints a, b, c
    }
}

1-3 不同长度的 Array 是不同的类型

Array 长度是数组类型的一个组成部分,因此 [3] int 和 [4] int 是不同的数组类型.

但是确认长度的数组 都属于 array 类型,所以 kind() 相同,可以通过 kind 进行判断

package main

import (
	"fmt"
	"reflect"
)

func main() {
   
	arrayA := [...]int{
   1, 2, 3}
	arrayB := [...]int{
   1, 2, 3, 4}
	fmt.Println(reflect.TypeOf(arrayA))
	// or
	//fmt.Printf("%T", arrayA)
	fmt.Println(reflect.TypeOf(arrayB))
	fmt.Println(reflect.TypeOf(arrayA) == reflect.TypeOf(arrayB))
	/*
	[3]int
	[4]int
	false
	*/
	fmt.Println(reflect.TypeOf(arrayA).Kind())
	fmt.Println(reflect.TypeOf(arrayB).Kind())
	/*
	array
	array
	*/
	fmt.Println(reflect.DeepEqual(reflect.TypeOf(arrayA).Kind(),reflect.TypeOf(arrayB).Kind()))
	fmt.Println(reflect.TypeOf(arrayA).Kind().String() == "array")
	/*
	true
	true
	*/

}

slice 是不定长的 array,所以即使长度不同,也为同一个类型

package main

import (
	"fmt"
	"reflect"
)

func main() {
   
	arrayC :=[]int{
   1,2,3}
	arrayD :=[]int{
   1,2,3,4}
	fmt.Println(reflect.TypeOf(arrayC)) // []int
	fmt.Println(reflect.TypeOf(arrayC).Kind()) // slice
	fmt.Println(reflect.TypeOf(arrayC) == reflect.TypeOf(arrayD)) // true
}

1-4 函数中 Array 参数是值传递

Go 中的数组传参时,是值传递,函数会的到原始数据的一份赋值数据,而非同一个内存地址。

package main
import "fmt"
func main() {
     
    x := [3]int{
   1,2,3}
  
    func(arr [3]int) {
   
        arr[0] = 7
        fmt.Println(arr) //prints [7 2 3]
    }(x)
  
    fmt.Println(x) 
  	//prints [1 2 3] (not ok if you need [7 2 3])
}

若需要使用同一个内存地址时,应该使用数组指针类型传参,引用传递

package main
import "fmt"
func main() {
     
    x := [3]int{
   1,2,3}
  	
  	// 指向参数 x
    func(arr *[3]int) {
   
        (*arr)[0] = 7
        fmt.Println(arr) //prints &[7 2 3]
    }(&x)
  
    fmt.Println(x) //prints [7 2 3]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值