golang切片內存應用技巧

在 Go 語言中切片是使用很是頻繁的一種聚合類型,它表明變長的序列,底層引用一個數組對象。一個切片由三個部分構成:指針、長度和容量。指針指向該切片本身第一個元素對應的底層數組元素的內存地址。git

切片的類型聲明以下:github

type slice struct {
  array unsafe.Pointer
  len   int
  cap   int
}
複製代碼

多個切片之間能夠共享底層數組的數據,而且引用的數組區間可能重疊。利用切片 的這個特性咱們能夠在原有內存空間中對切片進行反轉、篩選和去重等操做,這樣就不用聲明一個指向新內存的切片來存儲結果,從而節省了內存空間以及擴展底層數組的消耗,這在切片長度足夠大時效果就會很是顯著。golang

下面這些例子都是在切片底層數組的內存空間上進行的操做,須要注意的是這些操做在底層數組上生成新切片的同時也會更改底層數組。數組

刪除指定位置的元素

下面的函數從原切片中刪除索引位置i上的元素bash

func remove(slice []int, i int) []int {
    copy(slice[i:], slice[i+1:])
    return slice[:len(slice)-1]
}

func main() {
    s := []int{5, 6, 7, 8, 9}
    fmt.Println(remove(s, 2)) // "[5 6 8 9]"
}
複製代碼

內置的copy函數能夠方便地將一個切片複製另外一個相同類型的切片上。app

篩選元素

下面的函數從輸入的源切片中篩選出知足條件的切片元素,返回一個知足條件的元素組成的新切片。函數

type funcType func(T) bool //表明篩選邏輯函數,能夠按需實現 func filter(a []T, f funcType) []T {
    b := a[:0]
    for _, x := range a {
	    if f(x) { 
		    b = append(b, x)
	    }
    }
    return b
}
複製代碼

反轉切片

func reverse(a []T) []T {
    for i := len(a)/2-1; i >= 0; i-- {
        opp := len(a)-1-i
	    a[i], a[opp] = a[opp], a[i]
	}
		
	return a
}
複製代碼

分組切片

下面的函數接收一個[]int 類型的源切片actions, 返回一個按指定長度分組的嵌套切片(解釋起來好難,用過PHP 的同窗能夠理解爲 Go 版本的array_chunk 函數,沒用過的看下面例子)。假設切面值爲:[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},設置分組中元素長度batchSize爲3,函數調用後返回的分組後的切片爲[[0 1 2] [3 4 5] [6 7 8] [9]]ui

func chunk(actions []int, batchSize int) []int {
	var batches [][]int

	for batchSize < len(actions) {
    	actions, batches = actions[batchSize:], append(batches, actions[0:batchSize:batchSize])
	}
	batches = append(batches, actions)
		
    return batches
}

func main() {
	actions := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	batchSize := 3
    chunks = chunk(actions, batchSize)
    //chunks 爲[[0 1 2] [3 4 5] [6 7 8] [9]]
}
複製代碼

這裏順便說一下,完整的切片表達式形式以下:spa

input[low:high:max]
複製代碼

最後一個 max 的做用是,生成的切片的cap(容量)爲max - low指針

原地去重(只針對可比較的切片類型)

import "sort"

func main() {
	in := []int{3,2,1,4,3,2,1,4,1} // any item can be sorted
	sort.Ints(in)
	j := 0
	for i := 1; i < len(in); i++ {
        if in[j] == in[i] {
            continue
		}
		j++

		in[j] = in[i]
	}
	result := in[:j+1]
	fmt.Println(result) // [1 2 3 4] 
}
複製代碼

文章中部分例子來自golang 官方的 GitHub 的 wiki ,在這個 wiki 裏介紹了不少的切片使用技巧,瞭解更多能夠訪問golang 的 GitHub Wiki github.com/golang/go/w…

相關文章
相關標籤/搜索