温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2020-07-04 19:21:04 来源:网络 阅读:3468 作者:老逗先生 栏目:编程语言

这章主要描述如何定义变量、常量、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. 基础类型底层都是分配了一块内存,然后在分配的内存中存储了相应的值:
    go 语言中的类型及数据结构
    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赋值。
        go 语言中的类型及数据结构
        对于结构体类型,它是一种用户可以自定义的类型,它实际就是用其他类型组合成新的类型
        定义方式:
        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
        也可以通过下图进行理解
        go 语言中的类型及数据结构
      1. 字符串类型
        go 语言中的类型及数据结构
        通过上面的图我们可以看到,字符串在内存中表现为占用2-word,包含一个指向字符数据的指针和一个字符串长度。
        go 语言中的类型及数据结构
        从上面的结果我们可以看到,根本无法改变底层数组的某元素,这是很安全的。
        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
      go 语言中的类型及数据结构
      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)。如下:
      go 语言中的类型及数据结构
      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,….}
以下是两种定义例子
go 语言中的类型及数据结构
上面的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\t%d\n", name, ages[name])
}
map中如果没有该key则返回值为0,但是如果该key存在且键值是0,如何判断?
map功能的查找:
value, ok := map[“1”]
if ok{
//处理查到的value值
}
go 语言中的类型及数据结构

  • 6.零值
    零值,并非是空值,而是变量未赋值时默认的值,通常为0
    int int8 int32 int64 0
    uint 0x0
    rune 0 //实际就是int32
    byte 0x0 //实际就是uint8
    float32 float64 0
    bool false
    string “ ”
    参考文档:
    https://research.swtch.com/godata
    https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.2.md
    http://blog.csdn.net/slvher/article/details/44340531
    Go source code - src/pkg/runtime/hashmap.c
    https://golang.org/ref/spec#Map_types
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI