Go-数组类型详解(声明、初始化、遍历、多维数组等)

简介: Go-数组类型详解(声明、初始化、遍历、多维数组等)

上篇文章思考题

Go-基本数据类型转换详解

结果

0

可接收错误

strNum := "123.hello"
floatNum, er := strconv.ParseFloat(strNum,64)
fmt.Println(floatNum,er)

结果

0 strconv.ParseFloat: parsing "123.hello": invalid syntax

介绍

  • 数组是值类型,默认情况下作为参数传递给函数时会拷贝,不影响原数组。可通过形参为数组指针,实参为数组地址来修改。
  • 声明时,默认值为零值(0、""、false等)
  • 声明固定长度,不能动态变化
  • 元素的数据类型要相同
  • 占用内存连续

声明

var variable_name [SIZE]variable_type

代码

    //声明数组
    var arr [3]int

声明并初始化

var variable_name [SIZE]variable_type = [SIZE]variable_type{value1,value2...}

var variable_name = [SIZE]variable_type{value1,value2...}

variable_name := [...]variable_type{value1,value2...}

variable_name := [...]variable_type{index1:value1,index2:value2}

注意:size可以使用...省略,推导

//初始化数组
var arr1 [3]int = [3]int{1,2,3}
var arr2 = [3]int{1:4,0:5,2:6}
arr3 := [...]int{7,8,9}
arr4 := [5]int{1:3,3:5}

遍历

for循环,下标

  n1 := len(arr1)
  for i:=0;i<n1;i++{
    fmt.Print(arr1[i]," ")
  }

for range

for key,value := range

  for _,n := range arr3{
    fmt.Print(n," ")
  }

_是匿名变量,可以看之前的文章了解变量和常量。

内存

src->cmd->compile->internal->types->type.go

// Array contains Type fields specific to array types.
type Array struct {
  Elem  *Type // element type
  Bound int64 // number of elements; <0 if unknown yet
}
// NewArray returns a new fixed-length array Type.
func NewArray(elem *Type, bound int64) *Type {
  if bound < 0 {
    Fatalf("NewArray: invalid bound %v", bound)
  }
  t := New(TARRAY)
  t.Extra = &Array{Elem: elem, Bound: bound}
  t.SetNotInHeap(elem.NotInHeap())
  return t
}

TARRAY是Array指针,以arr4为例,Go会生成一个连续空间,将第一个的地址给arr4第一个值*Type,长度给arr4的第二个值Bound。

2020062310470442.png

  fmt.Printf("arr4:%v &arr4:%p &arr4[0]:%v &arr4[1]:%v\n",arr4, &arr4,&arr4[0], &arr4[1])

结果

arr4:[0 3 0 5 0] &arr4:0xc00000c450 &arr4[0]:0xc00000c450 &arr4[1]:0xc00000c458

以arr4为例,数组地址和第一个元素的地址一样,后面相差的为元素所占字节数,这里是int,所以差8。

数组作为参数

值传递

值传递,返回数组最大值下标

// 求数组最大值及下标
func getMax(arr [5]int)(int,int){
  maxValue := arr[0]
  index := 0
  for i,v := range arr{
    if v > maxValue {
      maxValue = v
      index = i
    }
  }
  return index, maxValue
}

注意:数组的长度也是数组类型的一部分,[2]int和[3]int是不一样的类型。如果你发现有人的代码写的[]int,可以传递任意长度的“数组”,那么,他说错了,他说的是切片而不是数组。

调用代码

index,value := getMax(arr4)

引用传递

//原地反转数组
func reverseArr(arr *[10]int){
  i:=0
  j:=len(*arr) - 1
  for{
    if i>=j{
      break
    }
    (*arr)[i],(*arr)[j] = (*arr)[j],(*arr)[i]
    i++
    j--
  }
}

调用代码

arr6 := [10]int{1,4,7,-9,99,2,5,78,22,33}
reverseArr(&arr6)

多维数组

以二维数组为例

二维数组:一维数组,每个元素是一维数组(首元素)地址,数组长度为列数

声明并初始化

var arr8 = [...][2]int{{1,2},{2,3}}
  arr9 := [1][2]int{{5,6}}
  fmt.Println("arr7 arr8 arr9",arr7,arr8,arr9)

遍历

for

  for i:=0;i<len(arr8);i++{
    for j:=0;j<len(arr8[0]);j++{
      fmt.Print(arr8[i][j]," ")
    }
    fmt.Println()
  }

for range

  for _,row := range arr8{
    for _,val:= range row{
      fmt.Print(val," ")
    }
    fmt.Println()
  }

内存

2020062310470442.png

大概应该是这样,是一维数组指针,没有记录Bound,因为一位数组有记录元素个数,就不必再记录一次了。由于不能.出Bound来,另外,也是刚入门Go,没有仔细阅读源代码,有大佬知道的话可以下方评论,或者等某天如果我发现错了,再回来改。

全部代码

package main
import "fmt"
// 创建26大小数组,存放A-Z
func alpha(){
  alpha := [26]byte{}
  var A byte = 'A'
  for i :=0;i<26;i++{
    alpha[i] = A + byte(i)
  }
  fmt.Printf("%c\n",alpha)
}
// 求数组最大值及下标
func getMax(arr [5]int)(int,int){
  maxValue := arr[0]
  index := 0
  for i,v := range arr{
    if v > maxValue {
      maxValue = v
      index = i
    }
  }
  return index, maxValue
}
//原地反转数组
func reverseArr(arr *[10]int){
  i:=0
  j:=len(*arr) - 1
  for{
    if i>=j{
      break
    }
    (*arr)[i],(*arr)[j] = (*arr)[j],(*arr)[i]
    i++
    j--
  }
}
func main() {
    //------------------声明数组------------------
    var arr [3]int
    //-----------------初始化数组-----------------
    var arr1 [3]int = [3]int{1,2,3}
  var arr2 = [3]int{1:4,0:5,2:6}
  arr3 := [...]int{7,8,9}
  arr4 := [5]int{1:3,3:5}
    fmt.Println("arr arr1 arr2 arr3 arr4:",arr,arr1,arr2,arr3,arr4)
  //-------------------遍历数组----------------
  n1 := len(arr1)
  fmt.Print("数组arr1:")
  for i:=0;i<n1;i++{
    fmt.Print(arr1[i]," ")
  }
  fmt.Println()
  fmt.Print("数组arr3:")
  for _,n := range arr3{
    fmt.Print(n," ")
  }
  fmt.Println()
  //--------------------内存----------------------
  fmt.Printf("arr4:%v &arr4:%p &arr4[0]:%v &arr4[1]:%v\n",arr4, &arr4,&arr4[0], &arr4[1])
  fmt.Println(&arr4[2])
  //-----------------数组做参数----------------------
  index,value := getMax(arr4)
    fmt.Println("arr4最大值的下标和值:",index,value)
  arr6 := [10]int{1,4,7,-9,99,2,5,78,22,33}
  reverseArr(&arr6)
    fmt.Println(arr6)
  //----------------------------二维数组----------------------------------
  //------------声明---------------
  var arr7 [2][3]int
  //-----------声明并初始化---------
  var arr8 = [...][2]int{{1,2},{2,3}}
  arr9 := [1][2]int{{5,6}}
  fmt.Println("arr7 arr8 arr9",arr7,arr8,arr9)
  //----------遍历-----------------
  fmt.Println("arr8:")
  for i:=0;i<len(arr8);i++{
    for j:=0;j<len(arr8[0]);j++{
      fmt.Print(arr8[i][j]," ")
    }
    fmt.Println()
  }
  fmt.Println("arr8:")
  for _,row := range arr8{
    for _,val:= range row{
      fmt.Print(val," ")
    }
    fmt.Println()
  }
  //------内存----------
  fmt.Printf("&arr8:%p &arr8[0]:%p &arr8[1]:%p &arr8[0][0]:%v &arr8[1][0]:%v",&arr8, &arr8[0], &arr8[1], &arr8[0][0], &arr8[1][0])
}

结果截图

2020062310470442.png

注意

  • 数组长度也是数组类型的一部分,所以即使元素类型相同,长度不同也是不一样的类型。
  • 如果两个数组大小相同元素可以使用==比较,那么,两个数组可以使用==判断是否相等,当所有元素都对应相等时,两个数组相等。

参考

Go-1.16.3源代码

思考题

有函数getMax

// 求数组最大值及下标
func getMax(arr [5]int)(int,int){
  maxValue := arr[0]
  index := 0
  for i,v := range arr{
    if v > maxValue {
      maxValue = v
      index = i
    }
  }
  return index, maxValue
}

以下调用,结果如何?

  nums := [6]int{7,4,2,6,8,3}
  index,max := getMax(nums)
  fmt.Println(max)

答案见下一篇文章:Go-切片类型详解(遍历、内存、追加、插入、删除等)

更多Go相关内容:Go-Golang学习总结笔记

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。

相关文章
|
4月前
|
存储 JSON Go
Go语言之空接口与类型断言
本文介绍了 Go 语言中空接口(`interface{}`)和类型断言的核心概念及其应用。空接口可存储任意类型数据,适用于通用函数、动态数据结构与 JSON 解析等场景;类型断言用于将接口变量还原为具体类型,推荐使用带 `ok` 的写法以避免程序崩溃。此外,文章通过示例讲解了 `type switch` 类型判断与 JSON 处理技巧,并总结了空接口的注意事项,强调滥用可能导致类型安全性降低。内容深入浅出,帮助开发者灵活运用这些特性。
102 15
|
4月前
|
算法 Go
Go语言模拟集合类型-《Go语言实战指南》
在 Go 语言中,虽然没有内建的集合(Set)类型,但可以通过 `map` 实现其功能。常用方式包括 `map[T]bool` 和更节省内存的 `map[T]struct{}`。前者以布尔值表示元素存在性,后者利用零内存开销的空结构体。文章介绍了集合的基本操作(添加、删除、判断、遍历),并通过封装示例展示如何创建自定义 Set 类型。这种实现方式适用于去重、唯一标记及集合运算等场景,简洁高效且易于扩展。
|
4月前
|
存储 安全 Go
Map的遍历与判断键是否存在-《Go语言实战指南》
本文介绍了 Go 语言中对 `map` 的常见操作,包括遍历所有项和判断键是否存在。通过 `for range` 可以遍历 `map` 的键值对、仅键或仅值(需忽略键)。注意,`map` 遍历顺序是随机的。判断键是否存在时,使用双赋值语法 `value, ok := map[key]`,其中 `ok` 表示键是否存在。直接访问不存在的键会返回类型的零值,可能导致逻辑错误。掌握这些机制可更安全高效地处理键值对数据。
|
3月前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
125 1
|
4月前
|
Go 索引
Go语言数组的定义与操作 - 《Go语言实战指南》
本文介绍了 Go 语言中的数组(Array)相关知识,包括定义、初始化方式(默认、显式、指定索引及自动推导长度)、访问与修改、遍历方法(for 循环和 for range)、值类型特性(复制行为)、多维数组支持以及其与切片的区别。数组是定长且同类型的集合,适合性能敏感场景,但实际开发中更常用动态的切片(slice)。
140 11
|
9月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
178 7
|
5月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
253 10
|
9月前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
190 67
|
7月前
|
存储 算法 Go
Go语言实战:错误处理和panic_recover之自定义错误类型
本文深入探讨了Go语言中的错误处理和panic/recover机制,涵盖错误处理的基本概念、自定义错误类型的定义、panic和recover的工作原理及应用场景。通过具体代码示例介绍了如何定义自定义错误类型、检查和处理错误值,并使用panic和recover处理运行时错误。文章还讨论了错误处理在实际开发中的应用,如网络编程、文件操作和并发编程,并推荐了一些学习资源。最后展望了未来Go语言在错误处理方面的优化方向。
|
9月前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
321 12