天天看點

Go學習筆記

Go

文章目錄

  • ​​Go​​
  • ​​變量​​
  • ​​指針​​
  • ​​Go函數​​
  • ​​Go面向對象​​
  • ​​繼承​​
  • ​​接口​​
  • ​​資料結構​​
  • ​​連結清單​​

變量

變量聲明

//1、單變量聲明,類型放在變量名之後,可以為任意類型
var 變量名 類型
var v1,v2,v3 string //多變量同類型聲明
//2、多變量聲明
var {
    v1 int
    v2 []int
}      

變量初始化

//1、使用關鍵字var,聲明變量類型并指派
var v1 int=10
//2、使用關鍵字var,直接對變量指派,go可以自動推導出變量類型
var v2=10
//3、直接使用“:=”對變量指派,不使用var,兩者同時使用會文法沖突,推薦使用
v3:=10      

匿名變量

//Go中所有聲明後的變量都需要調用到,當出現函數多傳回值,并且部分傳回值不需要使用時,可以使用匿名變量丢棄該傳回值
func GetName()(firstName,lastName,nickName string){
  return "May","Chan","Make"
}
_,_,nickName:=GetName()  //使用匿名變量丢棄部分傳回值      

指針

指針(pointer)在Go語言中可以被拆分為兩個核心概念:

  • 類型指針,允許對這個指針類型的資料進行修改,傳遞資料可以直接使用指針,而無須拷貝資料,類型指針不能進行偏移和運算。(類似Java中的引用)
  • 切片,由指向起始元素的原始指針、元素數量和容量組成。

每個變量在運作時都擁有一個位址,這個位址代表變量在記憶體中的位置。Go語言中使用在變量名前面添加​

​&​

​操作符(字首)來擷取變量的記憶體位址(取位址操作)

取位址操作符​

​&​

​和取值操作符​

​*​

​是一對互補操作符,​

​&​

​取出位址,​

​*​

​根據位址取出位址指向的值。

func main() {
    str := "test ptr"
    fmt.Println(&str) // &T  取變量T的記憶體位址值指派到ptr  0xc000010200  傳回的是指針類型
    fmt.Println(*&str) // *ptr 取指定記憶體位址對應的變量值 test ptr  傳回的是值類型
}      

變量、指針位址、指針變量、取位址、取值的互相關系和特性如下:

  • 對變量進行取位址操作使用​

    ​&​

    ​操作符,可以獲得這個變量的指針變量。
  • 指針變量的值是指針位址。
  • 對指針變量進行取值操作使用​

    ​*​

    ​操作符,可以獲得指針變量指向的原變量的值。

通過指針修改資料

// 交換函數
func swap1(a, b *int) {
    // 取a指針的值, 賦給臨時變量t
    t := *a
    // 取b指針的值, 賦給a指針指向的變量
    *a = *b
    // 将a指針的值賦給b指針指向的變量
    *b = t
}
func main() {
    // 準備兩個變量, 指派1和2
    x, y := 1, 2
    // 交換變量值
    swap1(&x, &y)
    // 輸出變量值
    fmt.Println(x, y)
}      

new() 函數可以建立一個對應類型的指針,建立過程會配置設定記憶體,被建立的指針指向預設值。

func new(Type) *Type

    // new() 建立指針的另一種手段
    str := new(string)
    *str = "test new"
    fmt.Println(str)  // 0xc000010200
    fmt.Println(*str)      

go和java類似,都是值傳遞,修改的是傳入值的副本

type Person struct {
    name string
    age int
}

func updateAge(p Person){
    p.age = 10
}

func updateAgeByPtr(p *Person) {
    p.age = 10
}

func main() {
    p := Person{age: 0,name: "kevin"}
    fmt.Println(p.age)
    updateAge(p) // go中是值傳遞
    fmt.Println(p.age)
    updateAgeByPtr(&p)
    fmt.Println(p.age)
}      

變量聲明而沒有指派,預設為零值,不同類型零值不同,例如字元串零值為空字元串;

指針聲明而沒有指派,預設為nil,即該指針沒有任何指向。當指針沒有指向的時候,不能對(*point)進行操作包括讀取,否則會報空指針異常。

var aPot *string
    fmt.Println(aPot)  // <nil>      

指針也是一種類型,不同于一般類型,指針的值是位址,這個位址指向其他的記憶體,通過指針可以讀取其所指向的位址所存儲的值。

函數方法的接受者,也可以是指針變量。無論普通接受者還是指針接受者都會被拷貝傳入方法中,不同在于拷貝的指針,其指向的地方都一樣,隻是其自身的位址不一樣。

Go函數

Go函數中隻關注匿名函數和閉包

所謂閉包就是函數的傳回值是也是一個函數

// case1
func foo1(x *int) func() {
  // 傳回值是一個函數
  return func() {
    *x = *x + 1
    fmt.Printf("foo1 val = %d\n", *x)
  }
}

// case2
func foo2(x int) func() {
  return func() {
    x = x + 1
    fmt.Printf("foo1 val = %d\n", x)
  }
}

func main() {

  x := 133
  f1 := foo1(&x)
  f1()
  fmt.Println(x)
  
  y := 100
  f2 := foo2(y)
  f2()
  fmt.Println(y)
}      

執行結果:

foo1 val = 134
134
foo1 val = 101
100      

case1和case2的差別在于值傳遞和引用傳遞的差別,go和Java一樣隻有值傳遞,這裡所說的引用傳遞是傳遞的是位址的值

閉包的延遲綁定

隻有在執行閉包函數的時候才會去尋找最新的函數環境

// case7  閉包的延遲綁定,
func foo7(x int) []func() {
    var fs []func()
    values := []int{1, 2, 3, 4, 5}
    for _, val := range values {
        fs = append(fs, func() {
            fmt.Printf("foo7 val = %d\n", x+val)
        })
    }
    return fs
}

func main()  {
    fs := foo7(11)
    for _, f := range fs{
        f()
    }
}      

答案是:(在用到的時候去尋找函數的最新環境,此時是val 是 5)

foo7 val = 16
foo7 val = 16
foo7 val = 16
foo7 val = 16      

Go面向對象

繼承

在Go語言中,并沒有顯式的繼承與顯式的接口實作(接口實作其實也算是一種繼承),Go對于繼承,是通過組合來實作的

// 繼承
type People struct {
  name string
  age int
}

type Teacher struct {
  People  // 以組合的方式引入
  teacherSomeThing string
}      

接口

go中的接口不能有變量,go中實作接口是基于方法,如果一個類實作了這個接口中所有的方法,那麼這個類就實作了這個接口

import "fmt"

// 隻有實作了接口中的所有方法才是實作了這個接口
type Usb interface {
    start()
    stop()
}

type Usb1 interface {
    start()
    stop()
}

// computer既實作了Usb1也實作了Usb接口
type computer struct {

}

// 實作start
func (c computer)start()  {
    fmt.Println("調用start")
}

// 實作stop
func (c computer) stop()  {
    fmt.Println("調用stop")
}

func testUsb(u Usb)  {
    u.start()
    u.stop()
}

func main()  {
    c := computer{}
    testUsb(c)
}      
// 内置的error接口,是一個正常的用于處理錯誤的接口。
// 其中 nil 表示沒有錯誤。
type error interface {
    Error() string
}      
type MyError struct {
    errorMsg string
}

func (error MyError) Error() string{
    return error.errorMsg
}

func main()  {
    myError := MyError{
        errorMsg : "catch error",
    }
    fmt.Println(myError.Error())
}      

資料結構

連結清單

下一篇: Go接口