goLang學習筆記(二)

Jsp發表於2018-08-15

十一:陣列和切片

不允許混合不同型別的元素

a:slice可以向後擴充套件,不可以向前擴充套件
b:s[i]不可以超越len(s),向後擴充套件不可以超越底層陣列cap(s)
c:新增元素時如果超越cap,系統會重新分配更大的底層陣列
d:由於值傳遞的關係,必須接收append的返回值
e:s = append(s,val)

1、陣列的宣告
    var a [3]int 宣告一個長度為3的整型陣列,陣列中的所有元素都被自動賦值為陣列型別的零值
    a := [3]int{12,13,19}
    a := [...]int{12,24,25}
    陣列的大小是型別的一部分,陣列不能調整大小

2、陣列是值型別
    go中的陣列是值型別而不是引用型別

3、陣列的長度
len(a)

4、使用range迭代陣列
    for i, v := range a {

    }

    for _, v := range a {

    }

5、多維陣列
    a := [2][2]string{
        {'dd', "dsd"},
        {"sc", "xs"},
    }

6、切片
    a:建立一個切片
        a := [5]int{23,343,43,43,43}    var b []int = a[1:4]
        c := []int{5,3,5}

    b:切片的修改
        切片所做的更改會反映在陣列中

    c:切片的長度和容量
        切片的容量是從建立切片索引開始的底層陣列中元素數
        切片可以重置容量

    d:使用make建立一個切片
        make( []T, len, cap)[]T    i := make([]int, 5, 5)
    e:追加切片元素
        1、切片是動態的,使用append可以將元素追加到切片上  append(s[]T,x...T)[]T
        2、當新的元素被新增到切片時,會建立一個新的陣列。現有的陣列被複制到這個新的陣列中,並返回這個新陣列的新切片中。
        3、切片型別的零值是nil,一個nil切片的長度和容量都是0。可以使用append函式將值追加到nil切片
        4、...運算子可以將一個切片新增到另一個切片中  food := append(veggies, fruits...)

    f:切片的函式傳遞
        當切片作為引數傳遞給函式時,函式內所做的更改也會在函式外可見

    g:切片的記憶體優化
        切片持有對底層陣列的引用。只要切片在記憶體中,陣列就不能被垃圾回收。假設有一個非常大的陣列,只要處理一小部分。
        解決方法L:使用copy函式生成一個切片的副本複製程式碼

十二:可變函式引數

func find(num int, nums ...int){

}
1、可變引數函式的工作原理是把可變引數轉換為一個新的切片 ,可以不給可變引數nums傳入任何引數, 
nums是一個長度和容量為0的nil切片

2、將切片直接傳入可變引數函式 在切片後面加...  切片將直接傳入函式,不再建立新的切片  
find(89,nums...)複製程式碼

十三:maps

map是在go中將值與鍵關聯的內建型別,通過相應的鍵可以獲取到值

1、如何建立map  map必須使用make函式初始化
    通過向map函式傳入鍵和值的型別,可以建立map。make(map[type of key]type of value)是建立map的語法
       personSalary := make(map[string]int) 鍵是string型別,值是int型別

2、給map新增元素
personSalary["steve"] = 1233

personSalary := map[string]int{
    "steve":1200,
    "jam":1500,
}
personSalary["mike"] = 9000

3、獲取map中的元素
   a: 獲取一個不存在的元素,會返回int型別的零值0
   b: 要想知道map中到底是不是存在這個key,ok為true,表示key存在
           value, ok := map[key]

   c:遍歷map中所有的元素需要用for range迴圈
        for key, value := range personSarlary{
            fmt.Printf(key,value)
        }
        使用for range遍歷map時,不保證每次執行程式獲取的元素順序相同

4、刪除map中的元素
    刪除map中key的語法是delete(map,key)

5、獲取map的長度
    len(personSalary)

6、map是引用型別
    和slices類似,map也是引用型別。

7、map的相等性
    map之間不能使用 == 操作符判斷, == 只能用來檢查map是否為nil複製程式碼

十四:字串

字串在go語言中有著自己特殊的實現,是一個位元組切片。go中的字串是相容Unicode編碼的,使用UTF-8進行編碼

1、單獨獲取字串的每一個位元組
    a:%x格式限定符用於指定16進位制編碼
        for i:= 0;i < len(s);i++{

        }
    b:%c格式用於列印字串中的字元   在uft-8編碼中,一個程式碼點可能會佔用超過一個位元組的空間,可以使用rune解決

2、rune
 rune是int32的別稱,在go中,rune表示一個程式碼點,程式碼無論佔用多少個位元組,都可以用一個rune表示
    func printChars(s string){
        runes := []rune(s)
        for i:= 0;i < len(runes);i++{
            fmt.Printf("%c",runes[i])
        }
    }

3、字串的for range迴圈
    for index, rune := range s{

    }

4、用位元組切片構造字串
    byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9}
    str := string(byteSlice)
    fmt.Println(str)
    用utf-8編碼的16進位制位元組,暑促是Cafe   16進位制換成10進位制也一樣

5、rune切片構造字串 runeSlice := []rune{0x0053,0x0065}  //16進位制的Unicode程式碼點

6、字串的長度
    uft8 package包中的func RuneCountInString(s string) (n int)方法用來獲取字串的長度,這個方法傳入一個字串
    然後返回字串中的rune的數量

7、字串是不可變的
    a:go中的字串是不可變的,一旦一個字串被建立,那麼它將無法被修改
    b:為了修改字串,可以把字串轉化為一個rune切片。然後這個切片可以進行任何想要的改變,然後轉化為一個字串
        func mutate(s []rune) string {
            s[0] = 'a'
            return string(s)
        }
        func main() {
            h := "hello"
            fmt.Println(mutate([]rune(h)))
        }複製程式碼

十五:指標

  • 要改變內容必須使用指標接收者
  • 結構過大也考慮使用指標接收者
  • 一致性:如果有指標接收者,最好都是指標接收者
  • 值接收者是go語言特有
  • 值/指標接收者均可接收值/指標

1、指標的宣告
    a:指標的變數型別為 *T,該指標指向一個T型別的變數
        b := 255    var a *int = &b
        &操作符用於獲取變數的地址
    b:指標的零值是 nil

2、指標的解引用
    指標的解引用可以獲取指標所指向的變數的值。將a解引用的語法是 *a

3、向函式傳遞指標引數
    change(val *int){
        *val = 55
    }

4、不要向函式傳遞陣列的指標,而應該使用切片
    a:把一個指向陣列的指標傳遞給這個函式     a[x]是(*a)[x]的簡寫形式
    b:最好使用切片修改陣列

5、go不支援指標運算複製程式碼

十六:結構體

1、結構體的宣告
    type Employee struct {
        firstName string
        lastName  string
        age       int
    }
    匿名結構體:
    var employee struct {
        fistName, lastName string
        age int
    }

2、建立匿名結構體
    emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "And",
        lastName:  "Nik",
        age:        31,
        salary:     50000,
    }

3、結構體的零值

4、結構體的指標
    emp8 := &Employee{"Sam", "And", 55, 6000}
    訪問欄位:(*emp8).firstName
            可以使用emp8.firstName來代替顯式的解引用 (*emp8).firstName

5、匿名欄位
    建立結構體時,欄位可以只有型別,而沒有欄位名。這樣的欄位稱為匿名欄位
    //含有兩個匿名欄位
    type Person struct {
        string
        int
    }
    雖然匿名欄位沒有名稱,但其實匿名欄位的名稱就預設為它的型別

6、巢狀結構體
    type Address struct {
        city,state string
    }
    type Person struct {
        name string
        age int
        address Address
    }

    var p = Person
    person.name = "nav"
    p.age = 50
    p.address = Address {
        city: 'Chi'
        state: "s"
    }

7、提升欄位
    如果結構體中有匿名的結構體型別欄位,則結構體內的欄位就稱為提升欄位。提升欄位就像是屬於
    外部結構體一樣,可以直接訪問

8、匯出結構體和欄位
    如果結構體名稱以大寫字母開頭,則是其他包可以訪問的匯出型別。如果結構體裡的欄位首字母大寫,
    也能被其他包訪問

9、結構體相等性
   a: 結構體是值型別,如果它的每一個欄位都是可比較的,則該結構體也是可比較的。
         如果兩個結構體變數的對應欄位相等,則這兩個變數也是相等的

   b:如果結構體包含不可比較的欄位,則結構體變數也不可比較
        type image struct {
            data map[int]int
        }複製程式碼

十七:方法

1:方法就是一個函式,在func這個關鍵字和方法名中間加入裡一個特殊的接受器型別。
 a: 接收器可以是結構體或非結構體型別,可以在方法內部訪問'
    type Employee struct {
        name string
    }
    func (e Employee) display() {

    }
b:方法呼叫
    emp1 := Employee{
        name: 'Sam'
    }
    emp1.display()

2、為什麼有了函式還需要方法
    a:go不是純粹的物件導向程式語言,而且go不支援類,基於型別的方法是一種實現和類相似行為的途徑
    b:相同名字的方法可以定義在不同的型別,而相同名字的函式是不被允許的

3、指標接收器和值接收器
    a:指標接收器的方法內部的改變對於呼叫者是可見的,值接收器不是這樣
    b:指標接收器使用:
        1:對方法內部的接收器所做的改變應該對呼叫者可見時
        2:結構體有很多欄位,在方法內部使用結構體作為值接收器需要拷貝整個結構體;使用
           指標接收器,只會傳遞一個指標到方法的內部使用

 4、匿名欄位的方法
     屬於結構體的匿名欄位的方法可以被直接呼叫,就像方法屬於定義匿名欄位的結構體一樣

5、方法中使用值接收器與在函式中使用值引數
    a:一個函式有一個值引數,只能接受一個值引數
    b:一個方法有一個值接收器,可以接受值接收器和指標接收器

6、方法職工使用指標接收器與在函式中使用指標引數
    函式中只接受指標,指標接收器的方法可以使用值接收器和指標接收器

7、在非結構體的方法上
    a:為了在一個型別上定義一個方法,方法的接收器型別定義和方法的定義應該在同一個包中
       func (a int) add(b int){
       // 嘗試把一個add方法新增到內建的型別int,不被允許,因為add方法的定義和int型別的定義不
         //再一個包中
       }

       type myInt int
       func (a myInt) add(b myInt) myInt{
        //這樣是可以的
       }複製程式碼

十八:介面一

1、介面
    a:在物件導向的領域裡:介面定義一個物件的行為
    b:在go語言中,介面就是方法簽名的集合。當一個型別定義裡介面中的所有方法,稱它實現裡介面
    介面指定裡一個型別應該具有的方法,並由該型別決定如何實現這些方法

2、介面的宣告與實現
    a:其他語言如java,要求一個類使用implement關鍵字,顯示的宣告該類實現類介面
    b:在go中一個型別包含類介面中宣告的所有方法,就隱式的實現類介面

3、介面的實際用途

4、介面的內部表示

5、空介面
    沒有包含方法的介面稱為空介面,空介面表示為interface{}.空介面沒有方法,所有型別都實現了空介面

6、型別斷言
    型別斷言用於提取介面的底層值。在語法i.(T)中,介面i的具體型別是T。
    使用v,ok := i.(T)不會報錯

7、型別選擇
    a:型別選擇用於將介面的具體型別與很多case語句所指定的型別進行比較
        switch i.(type){
            case string:
                fmt.Printtf('d')
            case int:
                fmt.Printf('x')
        }

    b:可以將一個型別和介面相比較。如果一個型別實現類介面,那麼該型別與其實現的介面可以互相比較複製程式碼

十九:介面二

1、實現介面:指標接受者與值接受者
    a:使用值接受者的方法,可以用值來呼叫,也能用指標呼叫
    b:對於使用指標接受者的方法,用一個指標或者一個可取得地址的值呼叫都是合法的。
        但介面中儲存的具體值不能取到地址

2、實現多個介面

3、介面的巢狀
    go語言沒有提供繼承機制,可以通過巢狀其他介面建立一個新介面

4、介面的零值
    介面的零值是nil,對於值為nil的介面。其底層值和具體型別都為nil,呼叫它的方法會產生異常。複製程式碼

二十:併發入門

1、併發是指立即處理多個任務的能力
    go語言原生支援併發,go使用go協程和通道來處理併發

2、並行是指同時處理多個任務
    並行並不一定會加快執行速度,因為並行執行的元件之間可能需要相互通訊複製程式碼


相關文章