go三大指针数据-slice,map,struct

最近学习:《The Way to Go》,中文名《Go 入门指南》记录下学习轨迹

一、slice

声明+初始化: var s []int = arr[start:end]
             s := []int{1,2,3}
slice=完整array
(1)slice1 := arr1[:] //arr1[0:len(arr1)]的缩写
(2)slice1 = &arr1

s == s[:i] + s[i:] // i是整数且0<=i<=len
arr1[3:] == arr1[3:len(arr1)]
arr1[:3] == arr1[0:3] //从第一个到第三个元素(不包括第四个)

去掉slice1的最后一个元素,slice1 = slice1[:len(slice1)-1]
slice2向后移动一位,slice2 = slice2[1:]
//注意:s2 = s2[-1:] 会导致编译错误,末尾不能移动。切片不能被重新分片以获取数组的前一个元素。


绝对不要用指针指向slice。切片已经是一个引用类型,所以它本身就是一个指针
//注意:slice,map,channel都是指针


生成切片(len=50,cap=100):
slice1 := make([]int, 50, 100)
slice2 := new([100]int)[0:50]

new() 和 make() 的区别:
(1)new(T)返回一个指向(类型为T,值为0的)地址的指针
   make(T)返回一个类型为T的初始值

(2)new(T)适用于值类型如:array和struct。相当于 &T{}
   make(T)只适用于3种内建的引用类型:map、slice、channel

(3)new(T)获取内存地址:获取的是存储指定变量内存地址的一个变量,对于变量内部结构并不会执行相应的初始化操作
   make(T)初始化并获取对应的内存地址:


slice的len(长度)和cap(容量)的计算
len(slice) = j - i
cap(slice) = 总数 - i


package main
import "fmt"
func main() {
    s := make([]byte, 5)
    fmt.Println(len(s)) //5
    fmt.Println(cap(s)) //5
    s = s[2:4] //i=2,j=4,总数=5
    fmt.Println(len(s)) //4-2=2
    fmt.Println(cap(s)) //5-2=3
}


package main
import "fmt"
func main() {
    s1 := []byte{'p', 'o', 'e', 'm'}
    s2 := s1[2:]
    fmt.Printf("s2=%+s\n", s2) //s2=em
    s2[1] = 't'
    fmt.Printf("s1=%+s,s2=%+s", s1, s2) //s1=poet,s2=et
}

bytes包
[]byte的切片,用bytes包专门提供它的操作方法

定义的3种方式:
(1)var buffer bytes.Buffer
(2)var r *bytes.Buffer = new(bytes.Buffer)
(3)func NewBuffer(buf []byte) *Buffer 创建一个Buffer对象并且用buf初始化好,用在从buf读取时

使用步骤如下:
var buffer bytes.Buffer          //定义
buffer.WriteString(s)            //塞字符串 
fmt.Print(buffer.String(), "\n") //输出


给定切片 sl,将一个 []byte 数组追加到 sl 后面。写一个函数 Append(slice, data []byte) []byte,该函数在 sl 不能存储更多数据的时候自动扩容
package main
import (
    "fmt"
)
func main() {
    sl := []byte {'a', 'u', 'z', 's'}
    data := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
    sliceVal := append(sl, data)
    fmt.Printf("slice = %+s \n", sliceVal) //slice = auzsgolang 
}
func append(slice, data []byte) []byte {
    sliceLen := len(slice)
    dataLen := len(data)
    newLen := sliceLen + dataLen
    // make新的切片时若容量大于原切片,需扩充
    newCap := cap(slice)
    if newLen > cap(slice) {
        newCap = newLen
    }
    newSlice := make([]byte, newLen, newCap)
    for sliceKey, sliceItem := range slice {
        newSlice[sliceKey] = sliceItem
    }
    for dataKey, item := range data {
        newSlice[dataKey + sliceLen] = item
    }

    return newSlice
}


把一个缓存 buf 分片成两个 切片:第一个是前 n 个 bytes,后一个是剩余的,用一行代码实现。
package main
import (
  "bytes"
  "fmt"
)
func main() {
  n := 4
  str := "hello,go!"
  var buffer bytes.Buffer
  buffer.WriteString(str)
  bPrefix, bSuffix := buffer.Bytes()[:n], buffer.Bytes()[n:]
  fmt.Printf("bPrefix=%s,bSuffix=%s\n", string(bPrefix), string(bSuffix))
  //bPrefix=hell,bSuffix=o,go!
}

如果a是一个切片,a[n:n]长度是多少?a[n:n+1] 的长度又是多少?
a[n:n]=[],    len(a[n:n])  =0  其中,0<=n<=cap,超过就报错
a[n:n+1]=a[n],len(a[n:n+1])=1  其中,0<=n<cap,超过就报错


package main
import "fmt"
func main() {
    slFrom := []int{1, 2, 3}
    slTo := make([]int, 10)

    n := copy(slTo, slFrom)
    fmt.Println(slTo)//[1 2 3 0 0 0 0 0 0 0]
    fmt.Printf("Copied %d elements\n", n) // n == 3

    sl3 := []int{1, 2, 3}
    sl3 = append(sl3, 4, 5, 6)
    fmt.Println(sl3)//[1 2 3 4 5 6]
}

//append在大多数情况下很好用,但是想完全掌控整个追加过程,要实现AppendByte
func AppendByte(slice []byte, data ...byte) []byte {
    m := len(slice)
    n := m + len(data)
    if n > cap(slice) { // if necessary, reallocate
        // allocate double what's needed, for future growth.
        newSlice := make([]byte, (n+1)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}


练习 7.9
练习 7.10


//InsertStringSlice 将切片插入到另一个切片的指定位置
package main
import "fmt"
func main() {
    src := []string{"a", "b", "c", "d", "e"}
    newstr := []string{"f", "g"}
    fmt.Println(insertSlice(2, newstr, src))
}
func insertSlice(index int, newstr []string, src []string) (ns []string) {
    ns = append(ns, src[:index]...) // 切片后加..., 相当于拆包成单个元素
    ns = append(ns, newstr...)
    ns = append(ns, src[index:]...)
    return
}
/* [a b f g c d e] */


// remove sub slice
package main
import "fmt"
func main() {
    s := []int{0, 1,2,3,4,5,6,7,8,9}
    fmt.Println(removeSub(s, 3, 7))
}
func removeSub(s []int, start int, end int) (ns []int) {
    for ix, num := range s {
        if start <= ix && ix < end {
            continue
        }
        ns = append(ns, num)
    }
    return
}
/* [0 1 2 8 9] */

二、map

声明:  var mp1 map[string]int
初始化: mp1 := map[string]int{"one":1, "two":2}


不要使用new,永远用make来构造map
map的返回值可以是任意的,可以用切片作为map的值,mp2 := make(map[int]*[]int)


//如果key1存在则ok == true,否则ok为false
if _, ok := map1[key1]; ok {
    
}

//从map1中删除key1
delete(map1, key1) 


package main
import "fmt"
func main() {
    map1 := make(map[int]float32)
    map1[1] = 1.0
    map1[2] = 2.0
    map1[3] = 3.0
    map1[4] = 4.0
    for key, value := range map1 {
        fmt.Printf("key is: %d - value is: %f\n", key, value)
    }
}
/*key is: 3 - value is: 3.000000
  key is: 1 - value is: 1.000000
  key is: 4 - value is: 4.000000
  key is: 2 - value is: 2.000000*/
注意map本质是散列表。不是按照key或valule的顺序排列。


map类型的切片
package main
import "fmt"
func main() {
    // Version A:
    items := make([]map[int]int, 5)
    for i:= range items {
        items[i] = make(map[int]int, 1)
        items[i][1] = 2
    }
    fmt.Printf("Version A: Value of items: %v\n", items)

    // Version B: NOT GOOD!
    items2 := make([]map[int]int, 5)
    for _, item := range items2 {
        item = make(map[int]int, 1) // item is only a copy of the slice element.
        item[1] = 2 // This 'item' will be lost on the next iteration.
    }
    fmt.Printf("Version B: Value of items: %v\n", items2)
}
/*Version A: Value of items: [map[1:2] map[1:2] map[1:2] map[1:2] map[1:2]]
Version B: Value of items: [map[] map[] map[] map[] map[]]*/
注意:应当像A版本那样通过索引使用切片的map元素。在B版本中获得的项只是map值的一个拷贝而已,所以真正的map元素没有得到初始化。

map的排序
将key或value拷贝到一个切片,再对切片排序,最后使用切片的for-range方法。
package main
import (
    "fmt"
    "sort"
)
var (
    barVal = map[string]int{"hotel": 16, "alpha": 34, "kili": 43, "indio": 87,"juliet": 65,"lima": 98}
)
func main() {
    fmt.Print("unsorted:")
    i := 0
    keys := make([]string, len(barVal))
    for k, v := range barVal {
        fmt.Printf("K=%v,V=%v; ", k, v)
        keys[i] = k
        i++
    }
    sort.Strings(keys)
    fmt.Println()
    fmt.Print("sorted:")
    for _, k := range keys {
        fmt.Printf("K=%v,V=%v; ", k, barVal[k])
    }
}
/*unsorted:K=hotel,V=16; K=alpha,V=34; K=kili,V=43; K=indio,V=87; K=juliet,V=65; K=lima,V=98; 
  sorted:K=alpha,V=34; K=hotel,V=16; K=indio,V=87; K=juliet,V=65; K=kili,V=43; K=lima,V=98;*/
 

三、struct

type struct1 struct {
    i1  int
    f1  float32
    str string
}

【声明】
t := new(struct1) //等价 var t *struct1 加 t = new(struct1)

【声明+初始化】
ms := &struct1{10, 15.5, "Chris"} 
等价于:
var ms struct1
ms = struct1{10, 15.5, "Chris"}
等价于:
ms := new(struct1)
ms.i1 = 10
ms.f1 = 15.5
ms.str= "Chris"

注意:值的顺序必须按照定义顺序赋值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值