热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang基础之数组

文章转载请注明出处www.leexide.com希望每一位寻求转载的朋友都能够按照要求进行,鼓励原创,尊重原创。微信公众号:DevOps运维运营之家QQ号码:1045

文章转载请注明出处www.leexide.com
希望每一位寻求转载的朋友都能够按照要求进行,鼓励原创,尊重原创。
微信公众号:DevOps运维运营之家
QQ号码:1045884038
E-mail:leexide@126.com
如有问题或建议,请关注微信公众号
golang基础之数组

1 数组介绍

数组是同一类型元素的集合。例如,整数集合 5,8,9,79,76 形成一个数组。Go 语言中不允许混合不同类型的元素,例如包含字符串和整数的数组。(注:当然,如果是 interface{} 类型数组,可以包含任意类型) 。

2 数组常见操作

一个数组的表示形式为 [n]Tn 表示数组中元素的数量,T 代表每个元素的类型。元素的数量 n 也是该类型的一部分 。

2.1 数组初始化

一维数组初始化如下

func main() {
    var a [4]int    //元素自动初始化为零[0 0 0 0]
    b := [4]int{2, 5}  //未提供初始化值得元素自动初始化为0  [2 5 0 0]
    c := [4]int{5, 3: 10} //可指定索引位置初始化 [5 0 0 10]
    d := [...]int{1, 2, 3} //编译器按初始化值数量确定数组长度 [1 2 3]
    e := [...]int{10, 3: 100} //支持索引初始化,但注意数组长度与此有关 [10 0 0 100]
    fmt.Println(a, b, c, d, e)
}

对于结构等复合类型,可省略元素初始化类型标签

package main

import "fmt"

func main() {
    type user struct {
        name string
        age  byte
    }

    d := [...]user{
        {"tom", 20},// 可省略元素类型。
        {"lee", 18},// 别忘了最后一行的逗号。
    }

    fmt.Printf("%#v\n", d)
}
/*output
[2]main.user{main.user{name:"tom", age:0x14}, main.user{name:"lee", age:0x12}}
*/

在定义多维数组时,仅第一维度允许使用“...”

package main

import "fmt"

func main() {
    a := [2][2]int{
        {1, 2},
        {3, 4},
    }

    b := [...][2]int{
        {10, 20},
        {30, 40},
    }

    c := [...][2][2]int{   //三维数组
        {
            {1, 2},
            {3, 4},
        },
        {
            {10, 20},
            {30, 40},
        },
    }

    fmt.Println(a)  //[[1 2] [3 4]]
    fmt.Println(b)  //[[10 20] [30 40]]
    fmt.Println(c)  //[[[1 2] [3 4]] [[10 20] [30 40]]]
}

多维数组定义

package main

import (
    "fmt"
)

var arr0 [5][3]int
var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}

func main() {
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 纬度不能用 "..."。
    fmt.Println(arr0, arr1)
    fmt.Println(a, b)
}

/*
output
[[0 0 0] [0 0 0] [0 0 0] [0 0 0] [0 0 0]] [[1 2 3] [7 8 9]]
[[1 2 3] [4 5 6]] [[1 1] [2 2] [3 3]]
 */
2.2 数组索引

数组的索引从 0 开始到 length - 1 结束

func main() {
    var a [3]int //int array with length 3
    a[0] = 12    // array index starts at 0
    a[1] = 78
    a[2] = 50
    fmt.Println(a)
}
2.3 数组是值类型

Go 中的数组是值类型而不是引用类型。这意味着当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本。如果对新变量进行更改,则不会影响原始数组。

func main() {
    a := [...]string{"USA", "China", "India", "Germany", "France"}
    b := a // a copy of a is assigned to b
    b[0] = "Singapore"
    fmt.Println("a is ", a)  //a is  [USA China India Germany France]
    fmt.Println("b is ", b)  //b is  [Singapore China India Germany France]
}

上述程序中,a 的副本被赋给 b。在第 4 行中,b 的第一个元素改为 Singapore。这不会在原始数组 a 中反映出来。

同样,当数组作为参数传递给函数时,它们是按值传递,而原始数组保持不变。

package main

import "fmt"

func changeLocal(num [5]int) {
    num[0] = 55
    fmt.Println("inside function ", num)
}

func main() {
    num := [...]int{5, 6, 7, 8, 8}
    fmt.Println("before passing to function ", num) 
    changeLocal(num) //num is passed by value
    fmt.Println("after passing to function ", num)
}

/*output
before passing to function  [5 6 7 8 8]
inside function  [55 6 7 8 8]
after passing to function  [5 6 7 8 8]
*/

在上述程序的 13 行中, 数组 num 实际上是通过值传递给函数 changeLocal,数组不会因为函数调用而改变。

值拷贝行为会造成性能问题,通常会建议使用 slice,或数组指针。

package main

import (
    "fmt"
)

func test(x [2]int) {
    fmt.Printf("x: %p\n", &x)
    x[1] = 1000
}
func main() {
    a := [2]int{}
    fmt.Printf("a: %p\n", &a)
    test(a)
    fmt.Println(a)
}
/*
output:
a: 0xc042062080
x: 0xc0420620c0
[0 0]
 */
2.4 数组长度和元素数量

通过将数组作为参数传递给 len 函数,可以得到数组的长度。 cap可以得到元素数量

package main

import "fmt"

func main() {
    a := [...]float64{67.7, 89.8, 21, 78}
    fmt.Println("length of a is", len(a)) //length of a is 4
    fmt.Println("num of a is",cap(a)) //num of a is 4
}

注意:内置函数len和cap都返回第一维度长度

package main

func main() {
    a := [2]int{}
    b := [...][2]int{
        {10, 20},
        {30, 40},
        {50, 60},
    }

    println(len(a), cap(a))   // 2 2
    println(len(b), cap(b))   // 3 3
    println(len(b[1]), cap(b[1]))  // 2 2
}

####2.5 使用 range 迭代数组

for 循环可用于遍历数组中的元素。

package main

import "fmt"

func main() {
    a := [...]float64{67.7, 89.8, 21, 78}
    for i := 0; i 

上面的程序使用 for 循环遍历数组中的元素,从索引 0 到 length of the array - 1

Go 提供了一种更好、更简洁的方法,通过使用 for 循环的 range 方法来遍历数组。range返回索引和该索引处的值。让我们使用 range 重写上面的代码。我们还可以获取数组中所有元素的总和。

package main

import "fmt"

func main() {
    a := [...]float64{67.7, 89.8, 21, 78}
    sum := float64(0)
    for i, v := range a { //range returns both the index and value
        fmt.Printf("%d the element of a is %.2f\n", i, v)
        sum += v
    }
    fmt.Println("\nsum of all elements of a", sum)
}

上述程序的第 8 行 for i, v := range a 利用的是 for 循环 range 方式。 它将返回索引和该索引处的值。 我们打印这些值,并计算数组 a 中所有元素的总和。

如果你只需要值并希望忽略索引,则可以通过用 _ 空白标识符替换索引来执行。

for _, v := range a { // ignores index  }

上面的 for 循环忽略索引,同样值也可以被忽略。

2.6 数组操作符操作

如元素类型支持"==,!="操作符,那么数组也支持此操作

package main

func main() {
    var a, b [2]int
    println(a == b)  //true

    c := [2]int{1, 2}
    d := [2]int{0, 1}
    println(c != d) //true
    /*
        var e, f [2]map[string]int
        println(e == f)  //invalid operation: e == f ([2]map[string]int cannot be compared)
    */
}

3 数组高级用法

3.1 多维数组

到目前为止我们创建的数组都是一维的,Go 语言可以创建多维数组。

package main

import (
    "fmt"
)

func printArray(a [3][2]string) {
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf("%s ", v2)
        }
        fmt.Printf("\n")
    }
}

func main() {
    a := [3][2]string{
        {"lion", "tiger"},
        {"cat", "dog"},
        {"pigeon", "peacock"}, // this comma is necessary. The compiler will complain if you omit this comma
    }
    printArray(a)
    var b [3][2]string
    b[0][0] = "apple"
    b[0][1] = "samsung"
    b[1][0] = "microsoft"
    b[1][1] = "google"
    b[2][0] = "AT&T"
    b[2][1] = "T-Mobile"
    fmt.Printf("\n")
    printArray(b)
}

/*output
lion tiger 
cat dog 
pigeon peacock 

apple samsung 
microsoft google 
AT&T T-Mobile 
*/

多维数组遍历

package main

import (
    "fmt"
)

func main() {
    var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
    for k1, v1 := range f {
        for k2, v2 := range v1 {
            fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
        }
        fmt.Println()
    }
}
/*
output:
(0,0)=1 (0,1)=2 (0,2)=3 
(1,0)=7 (1,1)=8 (1,2)=9 
 */
3.2 数组指针和指针数组

要分清指针数组和数组指针的区别。指针数组是指元素为指针类型的数组,数组指针是获取数组变量的地址。

package main

import "fmt"

func main() {
    x, y := 10, 20
    a := [...]*int{&x, &y}
    p := &a

    fmt.Printf("%T,%v\n", a, a)  //[2]*int,[0xc042062080 0xc042062088]
    fmt.Printf("%T,%v\n", p, p)  //*[2]*int,&[0xc042062080 0xc042062088]
}

可获取任意元素地址

func main() {
    a := [...]int{1, 2}
    println(&a, &a[0], &a[1])  //0xc042049f68 0xc042049f68 0xc042049f70
}

数组指针可以直接用来操作元素

func main() {
    a := [...]int{1, 2}
    p := &a

    p[1] += 10
    println(p[1])   //12
}

4 数组使用常见坑

定义数组类型时,数组长度必须是非负整型常量表达式,长度是类型组成部分。也就是说,元素类型相同,但长度不同的数组不属于同一类型。

例子:

func main() {
    var d1 [3]int
    var d2 [2]int
    d1 = d2 //cannot use d2 (type [2]int) as type [3]int in assignment
}

5 数组总结

  1. 数组:是同一种数据类型的固定长度的序列。

  2. 数组定义:var a [len]int,比如:var a [5]int,数组长度必须是常量,且是类型的组成部分。一旦定义,长度不能变。

  3. 长度是数组类型的一部分,因此,var a[5] intvar a[10]int是不同的类型。

  4. 数组可以通过下标进行访问,下标是从0开始,最后一个元素下标是:len-1。数组索引常用操作如下:

    for i := 0; i 
  5. 访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic

  6. 数组是值类型,赋值和传参会复制整个数组,而不是指针。因此改变副本的值,不会改变本身的值。

  7. 支持 "=="、"!=" 操作符,因为内存总是被初始化过的。

  8. 指针数组 [n]*T,数组指针*[n]T

推荐阅读
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
author-avatar
帅哥不潮_460
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有