zoukankan      html  css  js  c++  java
  • Go语言基础之数组

    1 数组概述

      数组是由一个固定长度、相同类型元素组成的连续序列,一个数组可以由零个或多个元素组成。数组存储的类型可以是内置类型,如整型或者字符串,也可以是某种结构类型。由于数组只能存储固定长度的相同类型的数据,所以在Go语言中很少直接使用。

      下图是数组的内部实现,其中方框内的代表数组里的元素,数组中的元素存储在一段连续的内存空间中,且每个元素可以用一个唯一的索引(下标)来访问,这样就可以以固定的速度索引数组中的任意数据,速度非常快。

    图1 数组的内部实现

      数组的下标是从0开始的,最后一个元素的下标是len-1,也就是数组的长度(元素个数)减1,如果访下标在合法范围之外,则触发访问越界,会panic。

    2 数组声明和初始化

    2.1 数组声明

    1 var 数量变量名 [元素个数]Type

      比如: var a [8]int ,数组的长度必须是常量,并且长度是数组类型的一部分,长度是数组的一个属性,一旦定义数组的长度不能变。于是  [5]int  和  [8]int  不是同一个类型。

    1 var a [5]int
    2 var b [8]int
    3 a = b    //不能这样使用,因为a和b不是同一个类型

    2.2 数组初始化

      数组的初始化有很多种方式:

    方式一:

      使用初始化列表来设置数组元素的值

    1  func main() {
    2     var array1 [3]int    //编译器会自动为数组初始化int类型的默认0值
    3     var numArray = [3]int{1, 2}        //指定初始值完成初始化    
    4     var cityArray = [3]string{"西安", "成都", "上海"}
    5     fmt.Println(array1)       //[0 0 0]
    6     fmt.Println(numArray)         //[1 2]
    7     fmt.Println(cityArray)        //[西安 成都 上海]
    8 }

    方式二:

      方式一的弊端:每次声明的数组为指定的长度的数组,而后要确保提供的初始值的个数和数组长度一致。那么方式二可以让编译器根据初始值的个数自行推断数组的长度,也就是自动计算声明数组的长度。代码如下:

     1 func main() {
     2     var testArray [3]int
     3     var numArray = [...]int{1, 2}
     4     var cityArray = [...]string{"西安", "上海"}
     5 
     6     fmt.Println(testArray)                           //[0 0 0]
     7     fmt.Println(numArray)                            //[1 2]
     8     fmt.Printf("numArray的类型是:%T
    ", numArray)     //numArray的类型是:[2]int
     9     fmt.Println(cityArray)                           //[西安 上海]
    10     fmt.Printf("cityArray的类型是:%T
    ", cityArray)   //cityArray的类型是:[2]string
    11 }

    方式三:

      声明数组并指定特定元素的值

    1 func main() {
    2     a := [...]int{1: 1, 10: 10}
    3     fmt.Println(a)                      //[0 1 0 0 0 0 0 0 0 0 10]
    4     fmt.Printf("a的类型是:%T", a)        //a的类型是:[11]int
    5 }

    2 数组的遍历

    2.1 for循环遍历

    1 func main() {
    2     //for循环遍历
    3     var cityArray = [...]string{"北京", "上海", "西安"}
    4 
    5     for i := 0; i < len(cityArray); i++ {
    6         fmt.Printf("cityArray[%d]=%v
    ", i, cityArray[i])
    7     }
    8 }

    2.2 for range遍历

      这是Go语言一种独有的结构,可以用来遍历访问数组的元素。

    for-range的基本语法

    1 for index, value := range array01 {
    2     ...
    3 }

    说明:

    1. 第一个返回值index是数组的下标
    2. 第二个value是在该下标位置的值
    3. index和value仅在for循环内部可见的局部变量
    4. 遍历数组元素的时候,如果不想使用下标index,可以直接把下标index标为下划线_
    5. index和value的名称不是固定的,即程序员可以自行指定,一般命名为index和value

    for-range的案例

     1 func main() {
     2     //演示for-range遍历数组
     3     heroes := [...]string{"钢铁侠", "蜘蛛侠", "绿巨人"}
     4 
     5     for i, v := range heroes {
     6         fmt.Printf("i=%v v=%v
    ", i, v)
     7         fmt.Printf("heroes[%d]=%v
    ", i, heroes[i])
     8     }
     9 
    10     for _, v := range heroes {
    11         fmt.Printf("元素的值=%v
    ", v)
    12     }
    13 }

    3 多维数组

      Go语言是支持多维数组的,这里以二维数组为例(数组中有嵌套数组)

    3.1 二维数组的定义

    1 func main() {
    2     a := [3][2]string{
    3         {"北京", "上海"},
    4         {"广州", "深圳"},
    5         {"成都", "重庆"},
    6     }
    7     fmt.Println(a) //[[北京 上海] [广州 深圳] [成都 重庆]]
    8     fmt.Println(a[2][1]) //支持索引取值:重庆
    9 }

    3.2 二维数组的遍历

     1 func main() {
     2     a := [3][2]string{
     3         {"北京", "上海"},
     4         {"广州", "深圳"},
     5         {"成都", "重庆"},
     6     }
     7     for _, v1 := range a {
     8         for _, v2 := range v1 {
     9             fmt.Printf("%s	", v2)
    10         }
    11         fmt.Println()
    12     }
    13 }
    14 
    15 // 输出
    16 // 北京    上海    
    17 // 广州    深圳    
    18 // 成都    重庆

      注意:多维数组只有第一层可以使用 ... 来让编译器推导数组长度,例如:

     1 //支持的写法
     2 a := [...][2]string{
     3     {"北京", "上海"},
     4     {"广州", "深圳"},
     5     {"成都", "重庆"},
     6 }
     7 //不支持多维数组的内层使用...
     8 b := [3][...]string{
     9     {"北京", "上海"},
    10     {"广州", "深圳"},
    11     {"成都", "重庆"},
    12 }

    4 数组使用的注意事项和细节总结

    • 数组是多个相同类型数据的组和,一个数组一旦声明/定义了,其长度是固定的,不能动态变化
    • 数组中的元素可以是任何数据类型,包括值类型和引用类型,但不能混用
    • 数组创建后,如果没有赋值,有默认值(零值)
     1 func main() {
     2     // 1. 数值(整数系列,浮点数系列):0
     3     // 2. 字符串:""
     4     // 3. 布尔类型:false
     5 
     6     var arr01 [3]float32
     7     var arr02 [3]string
     8     var arr03 [3]bool
     9     fmt.Printf("arr01=%v arr02=%v arr03=%v", arr01, arr02, arr03)
    10 }
    • 用数组的步骤:声明数组并开辟空间;给数组各个元素赋值(默认零值);使用数组
    • 数组的小标是从0开始的
    1 var arr [3]string
    2 var index int = 3
    3 arr[index] = "tom"    //因为下标是0-2,因此arr[3]就越界
    • 数组下标必须在指定范围内使用,否则报panic;数组越界
    • Go的数组属值类型,在默认情况下是值传递,因此会进行值拷贝,数组间不会相互影响
     1 //修改数组第一个下标对应的值
     2 func test(arr [3]int) {
     3     arr[0] = 0
     4     fmt.Println("test arr:", arr)
     5 }
     6 
     7 func main() {
     8     arr := [3]int{10, 20, 30}
     9     test(arr)
    10     fmt.Println("main arr:", arr)
    11 }
    • 如果想在其它函数中,去修改原来的数组,可以使用引用指针(指针方式)
     1 //修改数组第一个下标对应的值
     2 func test(arr *[3]int) {
     3     (*arr)[0] = 0
     4     // arr[0] = 0
     5     fmt.Println("test arr:", *arr)
     6 }
     7 
     8 func main() {
     9     arr := [3]int{10, 20, 30}
    10     test(&arr)
    11     fmt.Println("main arr:", arr)
    12 }
    • 长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度,看下面案例

         

    • 数组支持 “==“、”!=” 操作符,因为内存总是被初始化过的。
    • [n]*T表示指针数组,*[n]T表示数组指针 。

    5 数组的应用案例

      1、创建一个byte类型的26个元素的数组,分别放置'A'-'Z'。使用for循环访问所有元素并打印出来。

     1 func main() {
     2     // 思路
     3     // 1. 声明一个数组 var myChars [26]byte
     4     // 2. 使用for循环,利用字符可以进行运算的特点来赋值
     5     // 3. for循环打印
     6     var myChars [26]byte
     7 
     8     for i := 0; i < 26; i++ {
     9         myChars[i] = 'A' + byte(i) // 需要将i转换为byte类型
    10     }
    11 
    12     for i := range myChars {
    13         fmt.Printf("%c", myChars[i])
    14     }
    15 }
    View Code

      2、请求出一个数组的最大值,并得到对应的下标

     1 func main() {
     2     // 思路
     3     // 1. 随机生成5个随机数,将其存储在intArr数组中
     4     // 2. 假设下标为0的数最大
     5     // 3. 然后依次向后比较,如果发现更大,则交换
     6     var intArr [5]int
     7     len := len(intArr)
     8     rand.Seed(time.Now().UnixNano())
     9     for i := 0; i < len; i++ {
    10         intArr[i] = rand.Intn(100)
    11     }
    12 
    13     maxVal := intArr[0]
    14     maxValIndex := 0
    15 
    16     for i := 1; i < len; i++ {
    17         if maxVal < intArr[i] {
    18             maxVal = intArr[i]
    19             maxValIndex = i
    20         }
    21     }
    22     fmt.Println("intArr:", intArr)
    23     fmt.Printf("maxVal=%v maxValIndex=%v", maxVal, maxValIndex)
    24 }
    View Code

      3、请求出一个数组的和和平均值。for-range

     1 func main() {
     2     var intArr [5]int
     3     len := len(intArr)
     4 
     5     rand.Seed(time.Now().UnixNano())
     6     for i := 0; i < len; i++ {
     7         intArr[i] = rand.Intn(100)
     8     }
     9 
    10     fmt.Println("intArr:", intArr)
    11 
    12     sum := 0
    13     for _, val := range intArr {
    14         sum += val
    15     }
    16 
    17     // 如何让平均值保留到小数
    18     fmt.Printf("sum=%v 平均值=%v
    ", sum, float64(sum)/float64(len))
    19 }
    View Code

      4、随机生成五个数,并将其反转打印

     1 func main() {
     2     // 思路
     3     // 1. 随机生成五个数,rand.Intn() 函数
     4     // 2. 将随机数放入一个int数组内
     5     // 3. 反转打印,交换的次数是 len /2 ,倒数第一个和第一个元素交换
     6     var nums [5]int
     7     len := len(nums)
     8 
     9     // 为了每次生成的随机数不一样,需要给一个seed值
    10     rand.Seed(time.Now().UnixNano())
    11     for i := 0; i < len; i++ {
    12         nums[i] = rand.Intn(100) // 0 <= n < 100
    13     }
    14 
    15     fmt.Println("交换前:", nums)
    16 
    17     temp := 0
    18     for i := 0; i < len/2; i++ {
    19         temp = nums[len-1-i]
    20         nums[len-1-i] = nums[i]
    21         nums[i] = temp
    22     }
    23     fmt.Println("交换后:", nums)
    24 }
    View Code

      5、找出数组中和为指定值得两个元素的下标,比如从数组[1, 3, 5, 7, 8]中找出和为8的两个元素的下标分别为(0, 3)和(1, 2)。

     1 func main() {
     2     var nums = [...]int{1, 3, 5, 7, 8}
     3     for i := 0; i < len(nums); i++ {
     4         for j := i + 1; j < len(nums); j++ {
     5             if nums[i]+nums[j] == 8 {
     6                 fmt.Printf("(%d, %d)
    ", i, j)
     7             }
     8         }
     9     }
    10 }
    View Code
  • 相关阅读:
    Razor中@:和text
    Razor返回HTML字符串
    EPPlus使用
    ASP.NET MVC使用AllowAnonymous特性跳过授权验证
    下拉框获取json文件的数据
    SpringBoot 监听机制
    MybatisPlus Warpper实现复杂查询
    整合MybatisPlus心得
    MybatisPlus性能分析插件
    MybatisPlus物理删除、逻辑删除
  • 原文地址:https://www.cnblogs.com/dabric/p/12272815.html
Copyright © 2011-2022 走看看