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

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

定义变量

go中定义变量的方式不少:git

  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 = valuegithub

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

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

  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 语言中的类型及数据结构web

相关文章
相关标签/搜索