天天看點

Go:複合資料類型1、數組2、Slice3、Map4、結構體5、Json、文本和HTML模闆

文章目錄

  • 1、數組
  • 2、Slice
    • 1、概念
    • 2、函數
    • 3、Slice記憶體技巧
  • 3、Map
    • 1、map相關操作
    • 2、Map注意事項
  • 4、結構體
    • 1、基本概念
    • 2、結構體嵌入和匿名成員
  • 5、Json、文本和HTML模闆

1、數組

  • 數組是一個由固定長度的特定類型元素組成的序列,一個數組可以由零個或多個元素組成。
  • Go語言中很少直接使用數組。和數組對應的類型是Slice(切片),它是可以增長和收縮動态序列,slice功能也更靈活。
  • 内置的len函數将傳回數組中元素的個數
  • 預設情況下,數組的每個元素都被初始化為元素類型 對應的零值
  • 如果在數組的長度位置出現的是“…”省略号,則表示數組的長度是根據初始化值的個數來計算,,比如:
  • 可以直接通過==比較運算符來比較兩個數組,隻有當兩個數組的所有元素都是相等的時候數組才是相等的。
  • 數組是值類型,是以當一個數組指派給另一個數組的時候,數組2的改變不會影響數組1,可以了解為複制的操作
    s1 = [...]{1,2,3}
    	s2 = s1
    	s1[0] = 100    //s1 :[1,2,3]   s2:[100,2,3]
               

關于函數入參:

當調用一個函數的時候,函數的每個調用參數将會被指派給函數内部的參數變量,是以函數參數變量接收的是 一個複制的副本,并不是原始調用的變量。因為函數參數傳遞的機制導緻傳遞大的數組類型将是低效的,并且對數組參數的任何的修改都是發生在複制的數組上,并不能直接修改調用時原始的數組變量。

當然,我們可以顯式地傳入一個數組指針,那樣的話函數通過指針對數組的任何修改都可以直接回報到調用者。

關于函數入參是值傳遞還是引用傳遞可參考:飛雪無情

2、Slice

1、概念

  • Slice(切片)代表變長的序列,序列中每個元素都有相同的類型。
  • 一個slice類型一般寫作[]T,其中T代表slice中元素的類型。
  • slice的文法和數組很像,隻是沒有固定長度而已。切片是一個引用類型,指向底層的具體數組(數組改變,切片也會改變)
    var i1 = [5]int{1,2,3,4,5}
    	s1 := i1[0:3]
    	s2 := i1[:]
    	s1[1] = 200  //底層數組 i1 = {1,200,3,4,5} 切片s1: {1,200,3} 切片s2:{1,200,3,4,5}
    	s2[2] = 300  //底層數組 i1 = {1,200,300,4,5} 切片s1: {1,200,300} 切片s2:{1,200,300,4,5}
               
  • slice之間不能使用==操作符來判斷兩個slice是否含有全部相等元素,原因如下:
    Go:複合資料類型1、數組2、Slice3、Map4、結構體5、Json、文本和HTML模闆
  • 要測試一個slice是否是空的,使用len(s) == 0來判斷,而不應該用s == nil來判斷

2、函數

  • 内置的len和cap函數分别傳回slice的長度和容量,關于長度和容量的定義可參考:李文周-切片
  • slice的切片操作s[i:j],其中0 ≤ i≤ j≤ cap(s),用于建立一個新的slice,引用s的從第i個元素開始到第j-1個元素的子序列。
  • 從數組中擷取切片,這邊遵循的原則是左閉右開 ,s[i:] 表示 第i個元素到最後一個元素,s[:j] 表示第0個元素到第j-1個元素。s[:] 切片操作則是引用整個數組。
  • 因為slice值包含指向第一個slice元素的指針,是以向函數傳遞slice将允許在函數内部修改底層數組的元素,換句話說,複制一個slice隻是對底層的數組建立了一個新的slice别名
  • 在底層,make函數 建立了一個匿名的數組變量,然後傳回一個slice;隻有通過傳回的slice才能引用底層匿名的數組變量
    make([]T, len)
    	make([]T, len, cap) // same as make([]T, cap)[:len]
               
  • append函數 用于向slice追加元素,當slice的容量不足的時候,如果容量不夠直接指派會報錯,會通過擴容的方式生成一個新的slice ,是以不能确認在原先的slice上的操作是否會影響到新的slice。是以,通常是将append傳回的結果 直接 指派 給 輸入的slice變量
  • copy函數複制為值複制,也就是說指派一個新的底層數組,而被複制的切片對應的就是新的底層數組,是以修改對于被複制的數組和切片沒有影響,可參考:copy複制和等号複制的差別

3、Slice記憶體技巧

  • 直接覆寫原有數組的方式: out = append(out, s)
  • 用Slice模拟一個stack

    1、初始化stack 2、stack的頂部位置對應slice的最後一個元素: 3、通過收縮stack可以彈出棧頂的元素 4、要删除slice中間的某個元素并儲存原有的元素順序,可以通過内置的copy函數将後面的子slice向前依次移動一位完成:

    func remove(slice []int, i int) []int {
    		copy(slice[i:], slice[i+1:])
    		return slice[:len(slice)-1]
    	}
               
    如果删除元素後不用保持原來順序的話,我們可以簡單的用最後一個元素覆寫被删除的元素

3、Map

在Go語言中,一個map就是一個哈希表的引用,map類型可以寫為map[K]V,其中K和V分别對應key和value。其中K對應的key必須是支援==比較運算符的資料類型,是以map可以通過測試key是否相等來判斷是否已經存在。

1、map相關操作

建立map

内置的make函數可以建立一個map:

用map字面值的文法建立map:

ages := map[string]int{
		"alice": 31,
		"charlie": 34,
	}
           

通路map的值

Map中的元素通過key對應的下智語法通路:

ages["alice"] = 32
	
	fmt.Println(ages["alice"]) // "32"
           

判斷key是否存在的取法:

age, ok := ages["bob"]  //age表示key對應的value,ok表示key是否存在也就是value是否能取到
	if ok{}
           

删除map的值

2、Map注意事項

  • 在向map存資料前必須先建立map。
  • 所有這些操作是安全的,即使這些元素不在map中也沒有關系;如果一個查找失敗将傳回value類型對應的零值。
  • map中的元素并不是一個變量,是以我們不能對map的元素進行取址操作,禁止對map元素取址的原因是map可能随着元素數量的增長而重新配置設定更大的記憶體空間,進而可能導緻之前的位址無效:
  • Map的疊代順序是不确定的,每次都使用随機的周遊順序可以強制要求程式不會依賴具體的哈希函數實作。如果要按順序周遊key/value對,我們必須顯式地對key進行排序。

4、結構體

1、基本概念

  1. 結構體是一種聚合的資料類型,是由零個或多個任意類型的值聚合成的實體。
  2. 結構體變量的成員可以通過點操作符通路。
  3. 如果結構體成員名字是以大寫字母開頭的,那麼該成員就是導出的(外部可使用);這是Go語言導出規則決定的。一個結構體可能同時包含導出和未導出的成員.
  4. 一個命名為S的結構體類型将不能再包含S類型的成員:因為一個聚合的值不能包含它自身。
  5. 如果考慮效率的話,較大的結構體通常會用指針的方式傳入和傳回。
  6. 如果要在函數内部修改結構體成員的話,用指針傳入是必須的;因為在Go語言中,所有的函數參數都是值拷貝傳入的,函數參數将不再是函數調用時的原始變量。(重點)
  7. 如果結構體的全部成員都是可以比較的,那麼結構體也是可以比較的,那樣的話兩個結構體将可以使用==或!=運算符進行比較。

2、結構體嵌入和匿名成員

Go語言有一個特性讓我們隻聲明一個成員對應的資料類型而不指名成員的名字;這類成員就叫匿名成員。匿名成員的資料類型必須是命名的類型或指向一個命名的類型的指針。

聲明和通路:

type Point struct {
		X, Y int
		}
		
		type Circle struct {
			Point
			Radius int
		}
		//通路 Circle的X,Y
		var c Circle
		fmt.Println(c.X,c.Y)
           

初始化結構體

var c Circle
	c = Circle: Circle{
			Point: Point{
				X: 8,
				Y: 8
			},
			Radius: 5
		}
           

5、Json、文本和HTML模闆

參考原文

繼續閱讀