1. 程式人生 > >2. 內建容器

2. 內建容器

一. 陣列

陣列是值型別

  • [10]int 和 [20]int 是不同的型別
  • 呼叫func f(arr [10]int) 會拷貝 陣列
  • go語言中其實一般不直接使用陣列, 而是使用切片
package main

import "fmt"

func printArray(arr [5]int) { // [5]是值型別   []是一個切片, 兩者有很大區別
	arr[0] = 100 // 因為是值型別, 所以arr[0] 實際上沒有變為100, 只在函式內部變為100
	for i, v := range arr { // range 關鍵字  可以獲取 index  和value
		fmt.Println(i, v)
	}
}

func main() {
	// 陣列有多種定義方法
	var arr1 [5]int
	arr2 := [3]int{1, 3, 5}          // := 需要給初值
	arr3 := [...]int{2, 4, 6, 8, 10} // [...] 自動根據後面的 元素個數  確定陣列的容量
	var grid [4][5]int               // 二維陣列

	fmt.Println("array definitions:")
	fmt.Println(arr1, arr2, arr3)
	fmt.Println(grid) // 未賦值的元素  預設為0

	fmt.Println("printArray(arr1)")
	printArray(arr1)

	fmt.Println("printArray(arr3)")
	printArray(arr3)

	fmt.Println("arr1 and arr3")
	fmt.Println(arr1, arr3) //arr[0] 實際上沒有變為100
}


二. Slice (切片)

常用用法

package main

import "fmt"

func updateSlice(s []int) { //[] 裡沒有數字  就是個slice
	s[0] = 100
}

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}

	fmt.Println("arr[2:6] =", arr[2:6])
	fmt.Println("arr[:6] =", arr[:6])
	s1 := arr[2:]
	fmt.Println("s1 =", s1)
	s2 := arr[:]
	fmt.Println("s2 =", s2)
/*
arr[2:6] = [2 3 4 5]
arr[:6] = [0 1 2 3 4 5]
s1 = [2 3 4 5 6 7]
s2 = [0 1 2 3 4 5 6 7]
*/


	fmt.Println("After updateSlice(s1)")
	updateSlice(s1)
	fmt.Println(s1)
	fmt.Println(arr)
/*
After updateSlice(s1)
[100 3 4 5 6 7]
[0 1 100 3 4 5 6 7]
*/



	fmt.Println("After updateSlice(s2)")
	updateSlice(s2)
	fmt.Println(s2)
	fmt.Println(arr)
/*
After updateSlice(s2)
[100 1 100 3 4 5 6 7]
[100 1 100 3 4 5 6 7]
*/


	fmt.Println("Reslice")
	fmt.Println(s2)
	s2 = s2[:5]
	fmt.Println(s2)
	s2 = s2[2:]
	fmt.Println(s2)
/*
Reslice
[100 1 100 3 4 5 6 7]
[100 1 100 3 4]
[100 3 4]
*/
}

slice的擴充套件

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]    # 得到[2 3 4 5]
s2 := s1[3:5]     # 得到[5 6]
  • slice可以想後擴充套件, 不可以向前擴充套件
  • s[i] 不可以超越 len(s), 向後擴充套件不可以超越底層陣列cap(s)

 

 

 

 

 

 

 

 

 

 

 

 

 

package main

func main() {
	fmt.Println("Extending slice")
	arr[0], arr[2] = 0, 2
	fmt.Println("arr =", arr)
	s1 = arr[2:6]
	s2 = s1[3:5] // [s1[3], s1[4]]
	fmt.Printf("s1=%v, len(s1)=%d, cap(s1)=%d\n",
		s1, len(s1), cap(s1))
	fmt.Printf("s2=%v, len(s2)=%d, cap(s2)=%d\n",
		s2, len(s2), cap(s2))
/*
Extending slice
arr = [0 1 2 3 4 5 6 7]
s1=[2 3 4 5], len(s1)=4, cap(s1)=6   
s2=[5 6], len(s2)=2, cap(s2)=3   // 可以看到  6並不在s1中, 但s2依然可以獲取

// 但是 s1[4]  會報錯, 即下角標無法索引 cap, 只有slice 可以
*/
}

向Slice新增元素

  • cap的長度不會變, 但值是可以被改變的
  • 新增元素如果超越cap, 系統就會重新分配更大的底層陣列
	s3 := append(s2, 10)
	s4 := append(s3, 11)
	s5 := append(s4, 12)
	fmt.Println("s3, s4, s5 =", s3, s4, s5)
	// s4 and s5 no longer view arr.
	fmt.Println("arr =", arr)
	
	/*
	s3, s4, s5 = [5 6 10] [5 6 10 11] [5 6 10 11 12]
    arr = [0 1 2 3 4 5 6 10]     
    
    s3改變了cap的最後一個元素
    s4 s5 超越了cap
    s4 和 s5  的cap就不是arr了
    */

slice的操作

  • create slice
  • copy slice
  • Deleting elements from slice
  • Popping from front
  • Popping from back
package main

import "fmt"

func printSlice(s []int) {
	fmt.Printf("%v, len=%d, cap=%d\n",
		s, len(s), cap(s))
}

func sliceOps() {
	fmt.Println("Creating slice")
	var s []int // Zero value for slice is nil

	for i := 0; i < 100; i++ {
		printSlice(s) // cap 每次裝不下了, 就*2    0 1 2 4 8 16 32 64....
		s = append(s, 2*i+1)
	}
	fmt.Println(s)

	s1 := []int{2, 4, 6, 8}
	printSlice(s1)

	s2 := make([]int, 16)     // make 建立 16 長度的slice  但內容不知道
	s3 := make([]int, 10, 32) //  cap設定為32
	printSlice(s2)
	printSlice(s3)

	fmt.Println("Copying slice")
	copy(s2, s1)
	printSlice(s2) //[2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0], len=16, cap=16

	fmt.Println("Deleting elements from slice")
	s2 = append(s2[:3], s2[4:]...) // 刪除下標為3   s2[4:]...  表示 拆解s2[4:] 變成一個一個單獨引數 傳入
	printSlice(s2)                 //[2 4 6 0 0 0 0 0 0 0 0 0 0 0 0], len=15, cap=16

	fmt.Println("Popping from front")
	front := s2[0]
	s2 = s2[1:]

	fmt.Println(front) //2
	printSlice(s2)     //[4 6 0 0 0 0 0 0 0 0 0 0 0 0], len=14, cap=15

	fmt.Println("Popping from back")
	tail := s2[len(s2)-1]
	s2 = s2[:len(s2)-1]

	fmt.Println(tail) //0
	printSlice(s2)    //[4 6 0 0 0 0 0 0 0 0 0 0 0], len=13, cap=15
}

func main() {
	sliceOps()
}


三. Map

使用

  • 類似python的dict
package main

import "fmt"

func main() {
	// 三種建立方法--------------------------------------------------
	m := map[string]string{
		"name":    "ccmouse",
		"course":  "golang",
		"site":    "imooc",
		"quality": "notbad",
	}
	
	m2 := make(map[string]int) // m2 == empty map

	var m3 map[string]int // m3 == nil

	fmt.Println("m, m2, m3:")
	fmt.Println(m, m2, m3) //map[name:ccmouse course:golang site:imooc quality:notbad] map[] map[]

	// 遍歷方法--------------------------------------------------
	fmt.Println("Traversing map m")
	for k, v := range m {
		fmt.Println(k, v)
	}
	/*
	quality notbad
	name ccmouse
	course golang
	site imooc
	Getting values
	*/

	// 獲取元素--------------------------------------------------
	fmt.Println("Getting values")
	courseName := m["course"]
	fmt.Println(`m["course"] =`, courseName) // m["course"] = golang

	// 判斷map中key 是否存在--------------------------------------------------
	if causeName, ok := m["cause"]; ok { // 沒有cause這個key   ok是false的
		fmt.Println(causeName)
	} else {
		fmt.Println("key 'cause' does not exist")
	}

	// 刪除元素--------------------------------------------------
	fmt.Println("Deleting values")
	name, ok := m["name"]
	fmt.Printf("m[%q] before delete: %q, %v\n",
		"name", name, ok) //["name"] before delete: "ccmouse", true

	delete(m, "name") // 刪除
	name, ok = m["name"]
	fmt.Printf("m[%q] after delete: %q, %v\n",
		"name", name, ok) //m["name"] after delete: "", false
}

map的key

  1. map使用雜湊表, 必須可以比較是否相等
  2. 除了slice, map, function的 內建型別都可以作為key
  3. Struct型別不包含2中型別的欄位, 也可以作為key

map使用的例子

leetcode第3題

給定一個字串,找出不含有重複字元的最長子串的長度。

示例 1:

輸入: "abcabcbb"
輸出: 3 
解釋: 無重複字元的最長子串是 "abc",其長度為 3。
示例 2:

輸入: "bbbbb"
輸出: 1
解釋: 無重複字元的最長子串是 "b",其長度為 1。
示例 3:

輸入: "pwwkew"
輸出: 3
解釋: 無重複字元的最長子串是 "wke",其長度為 3。
     請注意,答案必須是一個子串,"pwke" 是一個子序列 而不是子串。
  • 解題
package main

import (
	"fmt"
)

func lengthOfNonRepeatingSubStr(s string) int {
	lastOccurred := make(map[rune]int)
	start := 0
	maxLength := 0

	for i, ch := range []rune(s) {
		if lastI, ok := lastOccurred[ch]; ok && lastI >= start {
			start = lastI + 1
		}
		if i-start+1 > maxLength {
			maxLength = i - start + 1
		}
		lastOccurred[ch] = i
	}

	return maxLength
}

func main() {
	fmt.Println(
		lengthOfNonRepeatingSubStr("abcabcbb"))
	fmt.Println(
		lengthOfNonRepeatingSubStr("bbbbb"))
	fmt.Println(
		lengthOfNonRepeatingSubStr("pwwkew"))
	fmt.Println(
		lengthOfNonRepeatingSubStr(""))
	fmt.Println(
		lengthOfNonRepeatingSubStr("b"))
	fmt.Println(
		lengthOfNonRepeatingSubStr("abcdef"))
	fmt.Println(
		lengthOfNonRepeatingSubStr("這裡是慕課網"))
	fmt.Println(
		lengthOfNonRepeatingSubStr("一二三二一"))
	fmt.Println(
		lengthOfNonRepeatingSubStr(
			"黑化肥揮發發灰會花飛灰化肥揮發發黑會飛花"))
}
/*
3
1
3
0
1
6
6
3
8
*/

字元和字串

  • rune uint32
  • byte uint8
  • 使用range 遍歷pos,rune對
  • 使用utf8.RuneCountInString獲得字元數量
  • 使用len獲取位元組長度
  • 使用[]byte獲得位元組
  • 使用[]rune獲得字元
package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	s := "Yes我愛慕課網!" // UTF-8
	fmt.Println(s)

	for _, b := range []byte(s) {  //byte   uint8
		fmt.Printf("%X ", b) //59 65 73 E6 88 91 E7 88 B1 E6 85 95 E8 AF BE E7 BD 91 21
	}
	fmt.Println()

	for i, ch := range s { // ch is a rune    即uint32    s是utf8的, 而ch是uint32   所以得到如下結果
		fmt.Printf("(%d %X) ", i, ch) //(0 59) (1 65) (2 73) (3 6211) (6 7231) (9 6155) (12 8BFE) (15 7F51) (18 21) 索引是不連續的
	}
	fmt.Println()

	fmt.Println("Rune count:",
		utf8.RuneCountInString(s)) //獲取字元數量    Rune count: 9

	bytes := []byte(s)
	for len(bytes) > 0 {
		ch, size := utf8.DecodeRune(bytes)
		bytes = bytes[size:]
		fmt.Printf("%c ", ch) //Y e s 我 愛 慕 課 網 !
	}
	fmt.Println()

	for i, ch := range []rune(s) {  // rune(s)轉化
		fmt.Printf("(%d %c) ", i, ch) //(0 Y) (1 e) (2 s) (3 我) (4 愛) (5 慕) (6 課) (7 網) (8 !)
	}
	fmt.Println()
}