1. 程式人生 > 其它 >go list指標_Go語言學習之路Day08

go list指標_Go語言學習之路Day08

技術標籤:go list指標

考試迫在眉睫,今天就簡要總結下吧。

b798a3de9fa5dce34b2e5d9866c9d311.gif

結構體

Golang沒有類(class),Go語言的結構體(struct)和其它程式語言的類(class)有同等的地位,你可以理解Golang是基於struct來實現OOP特性的。Golang仍然有面向物件程式設計的繼承,封裝和多型的特性,只是實現的方式和其它OOP語言不一樣,比如繼承:Golang沒有extends關鍵字,繼承是通過匿名欄位來實現。

如何宣告結構體

type 結構體變數名 struct{  欄位1 型別      // 結構體欄位=屬性=field  欄位2 型別}//欄位是結構體的一個組成部分,一般是基本資料型別、陣列,也可是引用型別。

1)欄位宣告語法同變數,示例:欄位名 欄位 型別

2)欄位的型別可以為:結構體中欄位的型別可以是任何型別,包括函式型別,介面型別,甚至結構體型別本身。

3)在建立一個結構體變數後,如果沒有給欄位賦值,都對應一個零值(預設值),規則同前面講的一樣:布林型別是false,數值是0,字串是""。陣列型別的預設值和它的元素型別相關,比如score[3]int則為[0,0,0]指標,slice,和map的零值都是nil,即還沒有分配空間。使用slice和map前一定要先make

4)不同結構體變數的欄位是獨立,互不影響,一個結構體變數欄位的更改,不影響另外一個,結構體是值型別。

在宣告結構體時我們也可以不給欄位指定名字,例如下面這樣:

type Person struct {  ID stringint//其中有一個int欄位沒有名字,這種我們稱其為匿名欄位。}

建立結構體變數和訪問結構體欄位

type Person struct {  name   string  age    int  adress string}  //方式一,直接宣告,然後在賦值  var person1 Person  person1 = Person{"mary", 22, "beijing"}  //方式二 宣告同時賦值  person2 := Person{"tom", 18, "beijing"}  //方式三 使用指標,先宣告指標,再賦值  var person3 *Person = new(Person)  (*person3).name = "jack"       //等價於 person3.name="jack"  (*person3).age = 25            //等價於 person3.age=25  (*person3).adress = "shanghai" //等價於  person3.address="shanghai"                                //go底層會將person3.address進行處理成 (*person3)  //方式四 使用指標同時賦值  var person4 *Person = &Person{"ali", 100, "wuhan"}  fmt.Println(person1, person2, *person3, *person4)
736d5f01eba38f20bd8c0bb4686264a4.png

思考:*person.age 和 (*person).age這類的運算順序是否一樣?

f6e935f1a21cc090408e4682f59cfa53.png

內嵌結構體

結構體作為一種資料型別也可以將其宣告為匿名欄位,此時我們稱其為內嵌結構體,下面這段程式碼中我們將結構體A嵌入到結構體B中。

type A struct {  X, Y int}type B struct {  A  Name string}

通過內嵌結構體的方式我們可以在結構體B的變數下很方便的操作A中定義的欄位。

b := new(B)b.X = 10b.Y = 20b.Name = "james"

可以看到在b中我們操作結構體A中定義的欄位就像結構體B本身定義的欄位一樣自然。

有關內嵌結構體的更多細節請大家自行搜尋學習,這裡面注意的東西還是很多的。

方法

方法與函式類似,只不過在方法定義時會在func和方法名之間增加一個引數,如下所示:

func(recevier type) methodName(引數列表)(返回值列表){  方法體  return 返回值}//1)引數列表:表示方法輸入//2)receviertype:表示這個方法和type這個型別進行繫結,或者說該方法作用於type型別//3)receivertype:type可以是結構體,也可以其它的自定義型別//4)receiver:就是type型別的一個變數(例項),比如:Person結構體的一個變數(例項)//5)返回值列表:表示返回的值,可以多個//6)方法主體:表示為了實現某一功能程式碼塊//7)return語句不是必須的。

我們來看個例子:

type Person struct {  name string}func (p Person) GetName() string {  return p.name}

其中GetName方法的接收者為p是Person結構體型別,也就是說我們為結構體Person綁定了一個GetName方法,我們可以使用如下的方式進行呼叫。

func main() {  p := Person{    name:"james",  }  fmt.Println(p.GetName())}

方法接收者

對於一個方法來說接收者分為兩種型別:值接收者和指標接收者。上面的GetName的接收者就是值接收者。我們再為Person結構體定義一個指標接收者。

func (p *Person)SetName(name string){  p.name = name}

使用值接收者定義的方法,在呼叫的時使用的其實是值接收者的一個拷貝,所以對該值的任何操作,都不會影響原來的型別變數。但是如果使用指標接收者的話,在方法體內的修改就會影響原來的變數,因為指標傳遞的也是地址,但是是指標本身的地址,此時拷貝得到的指標還是指向原值的,所以對指標接收者操作的同時也會影響原來型別變數的值。

介面

介面相當於一種規範,它需要做的是誰想要實現我這個介面要做哪些內容,而不是怎麼做。在go語言中介面的定義如下所示:

type Namer interface {    Method1(param_list) return_type    Method2(param_list) return_type    ...}

實現介面

在go語言中不需要顯示的去實現介面,只要一個型別實現了該介面中定義的所有方法就是預設實現了該介面,而且允許多個型別都實現該介面,也允許一個型別實現多個介面。

type Animal interface {  Eat()}type Bird struct {  Name string}func (b Bird) Eat() {  fmt.Println(b.Name + "吃蟲")}type Dog struct {  Name string}func (d Dog) Eat() {  fmt.Println(d.Name + "吃肉")}func EatWhat(a Animal) {  a.Eat()}func main() {  b := Bird{"Bird"}  d := Dog{"Dog"}  EatWhat(b)  EatWhat(d)}

在EatWaht函式中是傳遞一個Animal介面型別,上面的Bird和Dog結構體都實現了Animal介面,所以都可以傳遞到函式中去來實現多型特性。

但是還有幾點需要大家去探索一下:

  • 通過值接收者和指標接收者定義的方法,對於介面的實現有什麼影響嗎?

  • 還記得我們之前說過的內嵌結構體麼,如果嵌入的結構體實現了某個介面那麼對於外部的結構體有什麼影響嗎?

空介面

空介面是一個比較特殊的型別,因為其內部沒有定義任何方法所以空介面可以表示任何一個型別,比如可以進行下面的操作:

var any interface{}any = 1fmt.Println(any)any = "hello"fmt.Println(any)any = falsefmt.Println(any)
fa969f446660a6aa426193f9d98fd8a6.png

參考連結:

https://github.com/datawhalechina/go-talent/blob/master