高级数据类型(arrary、slice、map、ptr)

高级数据类型:

  高级数据类型有数组、切片、map、指针、结构体、函数、接口、通道等,本文只介绍Arrary、Slice、map、ptr。

数组:

(1)概念:

  数组是同一种数据类型的集合。数组从声明时大小就已经确定,使用过程中可以修改值,但是数组的大小不可改变。

(2)初始化

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

  var testArray[3]int

  var numArray=[3]int{4,5}

  方法二:自行推断数组的长度的方式

  var numArray=[...]int{4,5}

  方法三:使用指定索引值的方式来初始化数组

  var numArray=[...]int{1:4,3:5}

(3)数组的遍历

func main() {
    var a = [...]string{"南山", "罗湖", "保安"}
    // 方法1:for循环遍历
    for i := 0; i < len(a); i++ {
        fmt.Println(a[i])
    }

    // 方法2:for range遍历
    for index, value := range a {
        fmt.Println(index, value)
    }
}

(4)多维数组

func main() {
    a := [3][2]string{
        {"南山", "罗湖"},
        {"保安", "光明"},
        {"龙华", "龙岗"},
    }
    fmt.Println(a)
    fmt.Println(a[2][1]) //支持索引取值:龙岗
}

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

切片:

  切片是一个拥有相同类型元素的可变长度的序列,它非常灵活,支持自动扩容。切片是一个引用类型,它的内部结构包含:地址、长度、容量。

(1)为什么用切片:

  a.数组的内a容固定,不能自动扩展;

  b.值传递,b数组作为函数参数时,将整个数组拷贝一份给形参;

  go语言中,我们几乎可以在所有的场景中,用切片来替代数组。切片拥有自己的长度和容量,可以通过使用len()、cap()函数分别求切片的长度和容量。

(2)基于数组定义切片:

func main() {
    // 基于数组定义切片
    a := [5]int{15, 26, 37, 48, 59}
    b := a[1:4]                     //基于数组a创建切片,包括元素a[1],a[2],a[3]
    fmt.Println(b)                  //[26 37 48]
    fmt.Printf("type of b:%T\n", b) //type of b:[]int
        c := a[1:] //[26 37 48 59]
        d := a[:4] //[15 26 37 48]
        e := a[:]  //[15 26 37 48 59]
}

(3)切片再切片:

func main() {
    //切片再切片
    a := [...]string{ "南山区", "罗湖区", "光明区", "宝安区", "龙岗区", "龙华区"}
    fmt.Printf("a:%v type:%T len:%d  cap:%d\n", a, a, len(a), cap(a))
    b := a[1:3]
    fmt.Printf("b:%v type:%T len:%d  cap:%d\n", b, b, len(b), cap(b))
    c := b[1:5]
    fmt.Printf("c:%v type:%T len:%d  cap:%d\n", c, c, len(c), cap(c))
}

(4)使用make()函数构造切片:

  上面都是基于数组或切片来创建切片的,如果是动态创建一个切片,则用make([]T, size, cap)函数

(5)切片的本质:

  切片的本质就是对底层数组的封装,一个slice是一个轻量级的数据结构,提供访问数组子序列(或者全部)元素的功能。一个slice由三部分组成:指针、长度(len)、容量(cap),指针指向slice的第一个元素对应的底层数组元素的地址(并不一定是底层数组的首地址)

(6)切片的赋值拷贝

func main() {
    s1 := make([]int, 3) //[0 0 0]
    s2 := s1             //将s1直接赋值给s2,s1和s2共用一个底层数组
    s2[0] = 200
    fmt.Println(s1) //[200 0 0]
    fmt.Println(s2) //[200 0 0]
}

(7)切片的遍历

  切片支持索引遍历和for range遍历

func main() {
    s := []int{3, 8, 9}

    for i := 0; i < len(s); i++ {
        fmt.Println(i, s[i])
    }

    for index, value := range s {
        fmt.Println(index, value)
    }
}

(8)添加元素

func main() {
    //append()添加元素和切片扩容
    var numSlice []int
    for i := 0; i < 5; i++ {
        numSlice = append(numSlice, i)
        fmt.Printf("%v  len:%d  cap:%d  ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
    }
}

扩容策略

a.如果cap(申请容量)大于2倍old.cap(旧容量),则newcap=cap;

b.否则,如果old.cap<1024,则newcap=2*old.cap;

c.否则,如果old.cap>=1024,则最终容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap=old.cap,for {newcap += newcap/4})直到最终容量(newcap)大于等于新申请的容量(cap);

d.如果最终容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap);

(9)使用copy()函数复制切片

  copy(destSlice,srcSlice[]T)函数可以迅速将一个切片的数组复制到另一个切片空间中

func main() {
    // copy()复制切片
    a := []int{1, 2, 3, 4, 5}
    c := make([]int, 5, 5)
    copy(c, a)     //使用copy()函数将切片a中的元素复制到切片c
    fmt.Println(a) //[1 2 3 4 5]
    fmt.Println(c) //[1 2 3 4 5]
    c[0] = 20
    fmt.Println(a) //[1 2 3 4 5]
    fmt.Println(c) //[20 2 3 4 5]
       //说明copy后a和c的底层数组不是同一个数组
}

(10)从切片中删除元素

  go语言中没有删除元素的方法,可以使用切片本身的特殊性来删除元素。

func main() {
    // 从切片中删除元素
    a := []int{30, 31, 32, 33, 34, 35, 36, 37}
    // 要删除索引为2的元素
    a = append(a[:2], a[3:]...)
    fmt.Println(a) //[30 31 33 34 35 36 37]
}

要从切片a中删除索引为index的元素,方法是:a=append(a[:index],a[index+1:]...)

map:

(1)概念

  map是一种映射关系容器,是一种无序的基于key-value的数据结构,必须初始化后才可以使用,默认初始值为nil,需要make函数来分配内存。

  在map里所有的键都是唯一的,而且必须是支持==和!=操作符的类型,对于切片、函数以及包含切片的结构体等类型,由于具有引用语义,不能作为映射的键,键为这些类型编译会报错;map值可以是任意类型,所有键的类型必须相同,值也是如此。

注意:map是无序的,每次打印的顺序都可能不同。

(2)map的基本使用:

func main() {
    scoreMap := make(map[string]int, 8)
    scoreMap["张三"] = 200
    scoreMap["李四"] = 100
    fmt.Println(scoreMap)
    fmt.Println(scoreMap["李四"])
    fmt.Printf("type of a:%T\n", scoreMap)
}

输出:
map[小明:200 李四:100]
100
type of a:map[string]int

判断某个键是否存在:value,ok:=map[key]

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 100
    scoreMap["李四"] = 200
    // 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
    v, ok := scoreMap["张三"]
    if ok {
        fmt.Println(v)
    } else {
        fmt.Println("没有此人")
    }
}

map的遍历使用 for range

func main() {
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 50
    scoreMap["李四"] = 150
    scoreMap["王五"] = 200
    for k, v := range scoreMap {
        fmt.Println(k, v)
    }
}

注意:遍历map时的元素顺序与添加键值对的顺序无关。

使用delete()函数删除键值对:delete(map,key)

func main(){
    scoreMap := make(map[string]int)
    scoreMap["张三"] = 50
    scoreMap["小明"] = 150
    scoreMap["李四"] = 200
    delete(scoreMap, "小明")//将小明:150从map中删除
    for k,v := range scoreMap{
        fmt.Println(k, v)
    }
}

求map的键值对的容量,不能用cap()函数,而是用len(),map与slice一样可以自动扩容。

func main() {
    rand.Seed(time.Now().UnixNano()) //初始化随机数种子

    var scoreMap = make(map[string]int, 5)

    for i := 0; i < 10; i++ {
        key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
        value := rand.Intn(10)          //生成0~10的随机整数
        scoreMap[key] = value
    }
         for k,v:=range scoreMap{
               fmt.Println(k, v)
         }
}            

指针:

  指针是一个代表某个内存地址值,这个内存地址往往是在内存中存储另一个变量的起始位置。go语言的指针保留的应用不到C/C++ 的1/3,不过还是保留了对基本的内存操作。学习go语言指针只需记住两个符号:&(取地址)、*(根据地址取值/解引用)。

(1)栈帧(stack)

   a.用来给函数运行提供的内存空间

   b.当函数调用时,产生栈帧,函数调用结束,释放栈帧

   c.栈帧存储:局部变量、形参、内存字段描述

   d.栈帧的空间使用完后,会自己释放

(2)空指针和野指针

  空指针:未被初始化的指针

  野指针:被一片无效地址空间初始化

func main() {
    var a *int//空指针
    fmt.Println(*a)
    var p *int =0xc04204c080//野指针
    fmt.Println(*p)
}

(3)堆(heap)

  make、new的变量存在堆中,堆上申请的空间在c/c++上必须释放的,而go有垃圾回收(gc),但并不是就可以无限申请内存,因为堆的大小是有限的,所以为了能够循环地申请内存空间,在使用完后,或者不使用后,提示gc进行垃圾回收,可以通过赋nil值来提醒gc进行回收。

  func new(Type) *Type,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。

func main() {
    a := new(int)
    b := new(bool)
    fmt.Printf("%T\n", a) // *int
    fmt.Printf("%T\n", b) // *bool
    fmt.Println(*a)       // 0
    fmt.Println(*b)       // false
}

  指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应使用内置的new函数对指针进行初始化之后就可以正常对其赋值了。

func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)
}

  make也是用于内存分配的,区别于new,它只用于slice、map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。

make与new的差异

  a.二者都是用来分配内存

  b.make只用于slice、map、channel的初始化,返回的是这三个引用类型本身

  c.而new用于内存分配,初始值为类型的零值,返回的是指针

(4)变量存储

  等号左边的变量,代表变量所指向的内存空间;(写)

  等号右边变量,代表变量内存空间存储的数据值;(读)

func main() {
    var p *int
    p=new(int)
    *p=1000
    fmt.Printf("%d\n",*p)
    fmt.Printf("%v\n",*p)
}

(5)指针的函数参数

  传地址(引用):将形参的地址值作为函数参数

  传值(数据):将形参的值拷贝一份给实参

func main() {
        d := 99
    modifty1(d)
    fmt.Println(d)
    modifty2(&d)
    fmt.Println(d)
}

func modifty1(x int) {
    x = 100
}

func modifty2(x *int) {
    *x = 100
}

原文地址:https://www.cnblogs.com/juju-niuniu/p/12335481.html

时间: 2024-08-01 22:23:53

高级数据类型(arrary、slice、map、ptr)的相关文章

hive高级数据类型

hive的高级数据类型主要包括:数组类型.map类型.结构体类型.集合类型,以下将分别详细介绍. 1)数组类型 array_type:array<data_type> -- 建表语句 create table test.array_table( name   string, age    int, addr   array<string> ) row format delimited fields terminated by ',' collection items termina

GO語言基礎教程:array,slice,map

這節課我們來講解數組,切片和map,或許您是從其他語言轉到GO語言這邊的,那麼在其他語言的影響下您可能會不太適應GO語言的數組,因為GO語言把數組給拆分成了array,slice和map,接下來的時間讓我們一起研究一下這三者的差異以及用法.首先我們說一下array的部份: 1.數組的長度屬於數組的一部份,我們看下邊的例子 a:=[1]int{}和b:=[2]int{} a和b都是數組,但是他們的長度不同,在GO語言中會認為是不同的兩種類型,既然是不同的類型,那麼他們就不能進行比較或直接賦值的操作

Go语言基础(二)-----高级数据类型

Go语言-数组类型 一个数组(Array)就是一个可以容纳若干类型相同的元素的容器.这个容器的大小(即数组的长度)是固定的,且是体现在数组的类型字面量之中的.比如,我们声明了一个数组类型: type MyNumbers [3]int 注:类型声明语句由关键字type.类型名称和类型字面量组成. 所谓类型字面量,就是用于表示某个类型的字面表示(或称标记方法).相对的,用于表示某个类型的值的字面表示可被称为值字面量,或简称为字面量.比如之前提到过的3.7E-2就可被称为浮点数字面量. 类型字面量[3

Python笔记2#Python高级特性(Slice,Iteration, List Comprehensions,Generator)

▲切片Slice 在很多编程语言中,针对字符串提供了很多截取函数,其实目的就是对字符串进行切片.Python没有针对字符串的截取函数,只需要切片一个操作就能完成.Python切片非常灵活,一行代码就可以实现很多行循环才能完成的操作.示例代码如下: >>> L='ABCDEFG' >>> L[2:5] 'CDE' >>> L[:5] 'ABCDE' >>> L[-5:] 'CDEFG' >>> L[::2] 'ACEG

Python高级数据类型模块collections

collections模块提供更加高级的容器数据类型,替代Python的内置dict,list, set,和tuple  Counter对象 提供计数器,支持方便和快速的计数.返回的是一个以元素为键,出现次数为值的字典 cnt = Counter() #创建一个Counter对象lst =['red', 'blue', 'red', 'green', 'blue', 'blue']for word in lst: cnt[word] += 1print cnt # 输出:Counter({'bl

python 高级数据类型(列表 元祖 字典 字符串)

高级变量类型 目标 列表 元组 字典 字符串 公共方法 变量高级 知识点回顾 Python 中数据类型可以分为 数字型 和 非数字型 数字型 整型 (int) 浮点型(float) 布尔型(bool) 真 True 非 0 数 -- 非零即真 假 False 0 复数型 (complex) 主要用于科学计算,例如:平面场问题.波动问题.电感电容等问题 非数字型 字符串 列表 元组 字典 在 Python 中,所有 非数字型变量 都支持以下特点: 都是一个 序列 sequence,也可以理解为 容

JavaScript 基础知识系列:数据类型及slice(8,-1)

在基础类库中常见的slice(8,-1)是个什么鬼?下面就从js数据类型说起. javascrip数据类型有两种: 基本类型:Undefined,Null,Boolean,Number,String 引用类型: 第一类:原生对象:object,Array,Date,RegExp,Function以及有基本类型衍生出来的包装类型Boolean,Number,String: 第二类内置对象(JS语言提供的不依赖于执行宿主的对象,如Global,Math) 宿主对象(JS语言提供的任何依赖宿主环境的对

C++ 高级数据类型(三)—— 指针

我们已经明白变量其实是可以由标识来存取的内存单元.但这些变量实际上是存储在内存中具体的位置上的.对我们的程序来说,计算机内存只是一串连续的单字节单元(1byte cell),即最小数据单位,每一个单元有一个唯一地址. 计算机内存就好像城市中的街道.在一条街上,所有的房子被顺序编号,每所房子有唯一编号.因此如果我们说芝麻街27号,我们很容易找到它,因为只有一所房子会是这个编号,而且我们知道它会在26号和28号之间. 同房屋按街道地址编号一样,操作系统(operating system)也按照唯一顺

python 高级特性:slice(切片) 灵活指定范围

在python 官网的解释: class slice(stop) class slice(start, stop[, step]) Return a slice object representing the set of indices specified by range(start, stop, step). The start and step arguments default to None. Slice objects have read-only data attributes