go语言中的类型及数据结构

author author     2022-10-08     126

关键词:

这章主要描述如何定义变量、常量、go内置类型及go程序设计中的一些技巧

定义变量

go中定义变量的方式很多:

  1. 使用var关键字是最基本的定义变量的方式,与C语言有些不同,如下:
    var variable_name type
  2. 定义多个变量
    var name1,name2,name3 type
  3. 定义变量同时初始化
    var name1 string = "liming"
  4. 同时初始化多个变量
    var name1,name2,name3 string = "a", "c", "d"
  5. 直接忽略类型同时初始化
    var name1,name2,name3 = "a", "c", "d"
  6. 最简化的,只适用于函数内部使用,全局变量中无法使用,否则报错
    name1,name2,name3 := "a", "c", "d"

    常量

    常量就是确定的值,无法改变。(可以是布尔值、可以是字符串、数值等类型)
    语法如下:
    const name type = value

    内置基础类型(重点关注rune、byte、string类型)

    go语言中三种内置文本类型:string、(字节)byte、(符文)rune

  7. Boolean类型
    它的值只有ture和false,默认是false。定义如下:
    var a bool
  8. 数值类型
    带符号和不带符号两种。同时支持int和uint。这两种类型的长度一样。但具体长度由编译器决定。
    go里面也有直接定义好位数的类型:rune,int8,int16,int32,int64和byte,uint8,uint16,uint32,uint64。
    其中rune是int32的别名,byte是uint8的别名。具体可见官网。
    需要注意的是:不同类型的变量之间不允许互相赋值和操作,不然编译时会报错。
    浮点数的类型有float32和float64两种,默认是后者。
    复数:默认类型是complex128(64位实数+64位虚数)。还有complex64。
    var c complex64 = 6+5i //6是实数部分,5是虚数部分,i是虚数的单位。
    fmt.Printf("value is :%v",c)
  9. 字符串
    go中字符串采用的都是utf-8字符集编码。双引号或反引号括起来进行赋值。反引号所见即所得,双引号可以使用转义字符。
    var a string = "you"
    在go语言中字符串中的字符是不可变的,否则编译时会报错:cannot assign to s[0]
    var s string = "hello"
    s[0] = ‘c‘
    但是实际中会应用到更改字符串,可以采用变通的手法rune或byte。因为string类型在go中是以byte数组存储的,它不是以字符存储的。
    s:="hello"
    c:=[]rune(s) //这里也可以转成byte型数组。
    c[0]=‘c‘
    s1:=string(c)
    fmt.Println(s1)
    也可以通过切片的方式来实现更改字符串中的某一个字符
    s := "hello"
    s = "c" + s[1:]
    fmt.Println(s, s[2])
    操作字符串:
    s1,s2,s3:="I","am","studying"
    s4:=s1+s2+s3
    fmt.Println(s4)
  10. 错误类型
    error类型是go的内置类型。专门用来处理错误信息。go的package里面还有专门的包errors来处理错误:
    err := errors.New("emit macho dwarf: elf header corrupted")
    if err != nil {
    fmt.Print(err)
    }

    go数据底层的存储

  11. 基础类型底层都是分配了一块内存,然后在分配的内存中存储了相应的值:
    技术分享图片
    Even though i and j have the same memory layout, they have different types: the assignment i = j is a type error and must be written with an explicit conversion: i = int(j)
    通过上图,我们可以得知I,j,f同处在一个内存布局中。这句话有点不明白。float32尽管和int32有相同的内存占有量,但是处在不同的内存布局中。
      1. struct类型
        type Point struct{x,y int} //定义了一个结构体,下图是给变量p和pp赋值。
        技术分享图片
        对于结构体类型,它是一种用户可以自定义的类型,它实际就是用其他类型组合成新的类型
        定义方式:
        type variable_type_name struct{
        member1 type
        member2 type
        member3 type

        }
        声明变量的类型,如下,variable_name就是一个 variable_type_name类型,同时赋值
        variable_name := variable_type_name {value1,value2,value3,…}
        当然也可以采用以下的方式对成员进行赋值。
        variable_type_name.number1=value1
        在结构体中,成员占有的内存也是一个接一个连续的。如上图中pp和p的内存不在同一连续内存地址中,一个指向的是10和20的地址,一个是表示的10和20
        也可以通过下图进行理解
        技术分享图片
      1. 字符串类型
        技术分享图片
        通过上面的图我们可以看到,字符串在内存中表现为占用2-word,包含一个指向字符数据的指针和一个字符串长度。
        技术分享图片
        从上面的结果我们可以看到,根本无法改变底层数组的某元素,这是很安全的。
        Because the string is immutable, it is safe for multiple strings to share the same storage, so slicing s results in a new 2-word structure with a potentially different pointer and length that still refers to the same byte sequence。
        由于其底层不可变性,如果使用slice,则会造成不必要的浪费(因为只要有用到slice,就会保留该底层数组)。一般情况在大多数语言中都避免在字符串中使用slice。
    • 4.slice
      技术分享图片
      slice实际的底层也是数组,它通过[]或make定义切片。在内存中它是一个3-word的结构,它由ptr(a pointer to the first element of the array)、lenth和capacity组成。len是切片中索引的上线想x[i],而cap是切片容量的上线x[i;j],copy是用于复制,copy(s1,s2)
      slice string or array 不是一个copy,它仅仅创建了一个新的结构,这个结构包含ptr、len、cap
      ,它的底层是没有变化,如上图。
      Because slices are multiword structures, not pointers, the slicing operation does not need to allocate memory, not even for the slice header, which can usually be kept on the stack. This representation makes slices about as cheap to use as passing around explicit pointer and length pairs in C. Go originally represented a slice as a pointer to the structure shown above, but doing so meant that every slice operation allocated a new memory object. Even with a fast allocator, that creates a lot of unnecessary work for the garbage collector, and we found that, as was the case with strings above, programs avoided slicing operations in favor of passing explicit indices. Removing the indirection and the allocation made slices cheap enough to avoid passing explicit indices in most cases
    • 5.map类型
      它的结构体就是一张hashtable,关于具体的解释可以参考源码:
      $GOROOT/src/runtime/hashmap.go
      只截取一部分,自己可以详细的看。
      //A map is just a hash table. The data is arranged
      // into an array of buckets. Each bucket contains up to
      // 8 key/value pairs.
      官方给予的说明:
      A map is an unordered group of elements of one type, called the element type, indexed by a set of unique keys of another type, called the key type. The value of an uninitialized map is nil
      map类型是一个引用的类型,它修改键值可能会修改底层的hashtale,类似于slice(reference type)。如下:
      技术分享图片
      The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined for the dynamic key values; failure will cause a run-time panic.
      这里参考文档:
      http://blog.csdn.net/slvher/article/details/44340531
      Go source code - src/pkg/runtime/hashmap.c
      https://golang.org/ref/spec#Map_types

map类型类似于python中字典。实际就是键值对的集合。语法格式如下:
声明变量,默认map是nil,nil map不能直接赋值,默认是0
var map_variable_name map[key_data_type]value_data_type
使用make函数创建一个非nil的map,因为nil map不能存放键值对。
map_variable_name = make(map[key_data_type]value_data_type,cap)
简洁的:map_variable_name := map[key_data_type]value_data_type{k1:v1,k2:v2,….}
以下是两种定义例子
技术分享图片
上面的cap可以省略,但是在用时最好合理设置,为什么?
如果里面的key-value键值对超出容量,则容量会自动扩容(因为每一次的扩容都是重新分配内存和拷贝)
map中的key是独一无二的。
使用len()可以获得元素个数
使用delete()可以操作键值对的删除
delete(key,value) //注意不能是nil map,否则会抛出异常panic。
使用for….range对map进行迭代操作。
map的读取和设置类似于slice,通过key来进行操作,但是又有所不同,map中key可以是int、string、float(最好不用float)(只要是支持==或者!=类型的都可以,这里函数、map、slice不支持),而slice中的索引只能是int类型。value可以是其他任意类型。
map查找比线性搜索快,但是比使用索引访问数据的类型慢很多(据说慢100倍)。
注意:
1)map中的元素不是变量,因此不能寻址。具体原因是:map可能会随着元素的增多重新分配更大的内存空间,旧值都会拷贝到新的内存空间,因此之前的地址就会失效。
2)map中使用for…range遍历,(也就是说不能使用索引的方式获取键值,但是可以重新赋值)同时它的迭代顺序是不确定的,也就是说每执行一次结果的顺序都可能不同。在go语言中是有意的这么设计,是为例避免程序依赖于某种哈希实现,目的是为了程序的健壮。如果非要按顺序遍历,必须显示对key排序,可以使用sort包中的String函数。代码如下,一般最好不要这样使用。
import “sort”
var names []string
for ,name := range ages {
names = append(names, name)
}
sort.Strings(names)
for
, name := range names {
fmt.Printf("%s %d ", name, ages[name])
}
map中如果没有该key则返回值为0,但是如果该key存在且键值是0,如何判断?
map功能的查找:
value, ok := map[“1”]
if ok{
//处理查到的value值
}
技术分享图片

go语言自学系列|go语言数据类型

视频来源:B站《golang入门到项目实战[2021最新Go语言教程,没有废话,纯干货!持续更新中...]》一边学习一边整理老师的课程内容及试验笔记,并与大家分享,侵权即删,谢谢支持!​​​​在Go编程语言中,数据类型用于声明... 查看详情

Go 语言中的引用类型令人困惑

...】:2015-02-2607:48:12【问题描述】:我试图用Go语言制作Trie数据结构,但不知何故它遇到了引用问题,这里是。http://play.golang.org/p/ASSGF5Oe9R//Packagemainprovides...packagemainimport"fmt"typeRootTrie[] 查看详情

《go语言实战》go类型:基本类型引用类型结构类型自定义类型

Go语言是一种静态类型的编程语言,所以在编译器进行编译的时候,就要知道每个值的类型,这样编译器就知道要为这个值分配多少内存,并且知道这段分配的内存表示什么。提前知道值的类型的好处有很多,比如编译器可以合... 查看详情

我的go+语言初体验——go+语言数据类型(代码片段)

...。在程序设计语言中,采用数据类型来描述程序中的数据结构、数据范围和数据在内存中的存储分配。Go+对于数据类型有严格的定义,相同类型的值才能进行比较,兼容类型的值才能进行运算。如果值的类型是接... 查看详情

一文了解go中的指针和结构体

耐心和持久胜过激烈和狂热。前言前面的两篇文章对Go语言的基础语法和基本数据类型以及几个复合数据类型进行介绍,本文将对Go里面的指针和结构体进行介绍,也为后续文章做铺垫。指针在​​Go​​​语言中,指针可以简单... 查看详情

go语言常量和变量(代码片段)

Go语言数据类型Go语言本质是用C语言编写的一套高级开发语言,所以Go语言中的数据类型大部分都是由C语言演变而来的C语言数据类型Go语言数据类型C语言各数据类型占用内存空间类型32位编译器64位编译器char11int44float44double88short22l... 查看详情

go基础1(代码片段)

...符串类型转换fmt.Printf中的占位符输出类型Go是静态编译型语言 。Go和C语言类似,要先编译再执行,即编译型语言。Python、JavaScript等是动态解释型语言 查看详情

go语言中的结构体

参考技术A作为C语言家族的一员,go和c一样也支持结构体。可以类比于java的一个POJO。在学习定义结构体之前,先学习下定义一个新类型。新类型T1是基于Go原生类型int定义的新自定义类型,而新类型T2则是基于刚刚定义的类型T1,... 查看详情

go语言学习笔记—基础—复合数据类型—结构体:结构体方法(行为)(代码片段)

go中的方法是一种作用于特定类型变量(也即接收器receiver)的函数。如果把特定类型理解为结构体或类时,接收器receiver类似于python中的self。在go中,接收器receiver可以是任何类型和结构体;任何类型都可以拥... 查看详情

5.4go语言中自定义类型与结构体(struct)

Go是面向对象的语言吗在很多文章中都提到,Go语言中的struct某种意义就是对应其他语言中的class,就该问题特意阅读了Go语言官网的常见问题,有这样的描述IsGoanobject-orientedlanguage?Yesandno.AlthoughGohastypesandmethodsandallowsanobject-orienteds... 查看详情

5.4go语言中自定义类型与结构体(struct)

Go是面向对象的语言吗在很多文章中都提到,Go语言中的struct某种意义就是对应其他语言中的class,就该问题特意阅读了Go语言官网的常见问题,有这样的描述IsGoanobject-orientedlanguage?Yesandno.AlthoughGohastypesandmethodsandallowsanobject-orienteds... 查看详情

go语言学习笔记—基础—基本数据类型—字符串(11):go中的字符串

string是数据类型,不是引⽤或指针。其零值是空字符串"",而不是nilstring是只读的byteslice,使用len函数可以返回它所包含的byte数string的byte数组可以存放任何数据,如可见字符(汉字、英文字母、数字ÿ... 查看详情

go数据类型(三)整型及运算符

...nt16,uint16int32,uint32int64,uint64int,uint,uintptrGo为强类型语言,所以上述类型默认为不同类型如需运算,可通过强制类型转换+,-,*,/,%>,<,==,>=,<=和!=比较运算符计算的结果是布尔值位与:x&y位或:x|y异或:x^y取... 查看详情

go语言数组和切片(代码片段)

数组和C语言一样,Go语言中也有数组的概念,Go语言中的数组也是用于保存一组相同类型的数据和C语言一样,Go语言中的数组也分为一维数组和多维数组一维数组格式:vararr[元素个数]数据类型和C语言中数组不同,Go语言中数组定义之后... 查看详情

go语言中的array,slice,map和set

...以通过唯一的索引值访问,从0开始。数组是很有价值的数据结构,因为它的内存分配是连续的,内存连续意味着可是让它在CPU缓存中待更久,所以迭代数组和移动元素都会非常迅速。数组声明和初始化通过指定数据类型和元 查看详情

go中的struct

1.用来自定义复杂数据结构2.struct里面可以包含多个字段(属性),字段可以是任意类型3.struct类型可以定义方法,注意和函数的区分4.struct类型是值类型5.struct类型可以嵌套6.Go语言没有class类型,只有struct类型1.struct声明:type标... 查看详情

go语言基础之基本数据类型

Go语言基础之基本数据类型Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道(channel)等。Go语言的基本类型和其他语言大同小异。目录整形整型分为以下两... 查看详情

go语言基础之基本数据类型(代码片段)

Go语言中数据类型极其丰富,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道channel等。Go语言的基本类型和其他语言大同小异。基本数据类型整型整型分为以下两个大类:按长度分为:i... 查看详情