golang面向對象

一、方法

1、方法是作用在指定的數據類型上,和指定的數據類型綁定,因此自定義類型都可以有方法,而不僅僅是struct;

2、方法的申明和格式調用:

package main
import (
    "fmt"
)

type Person struct{
    Name string
}

func (p Person) test(){
    fmt.Println(p.Name)
}

func main(){
    p := Person{Name: "Tom"}
    p.test()
}

注意:結構體對象傳入方法中是值傳遞,和函數傳遞參數一樣。如果在方法中改變結構體變數的值,可以通過結構體指針的方式來處理。

package main
import (
    "fmt"
)

type Person struct{
    Name string
}

func (p *Person) test(){
    fmt.Println((*p).Name)
}

func main(){
    p := &Person{Name: "Tom"}
    p.test()
}

二、封裝:

1、什麼是封裝?

封裝就是把抽象出的欄位和對欄位的操作封裝在一起,數據被保護在內部,程式的其它包只有通過被授權的操作方法才能對欄位就行操作。

2、封裝的好處:

1)隱藏實現細節;

2)可以對數據進行驗證,保證數據安全合理。

3、golang中如何實現封裝?

package main
import (
    "fmt"
)

type person struct{
    Name string
    age int
}

func NewPerson(name string) *person {
    p := person{
        Name: name,
    }

    return &p
}

func (p *person) SetAge(age int){
    if age > 0 && age < 150{
        (*p).age = age
    } else {
        fmt.Println("對不起,你輸入的年齡範圍不正確。")
    }
}

func (p *person) GetAge() int {
    return (*p).age
}

func main(){
    p := NewPerson("Tom")
    p.SetAge(22)
    fmt.Println(p.Name)
    fmt.Println(p.GetAge)
    fmt.Println(*p)
}

// Tom
// 0xbc5a60
// {Tom 22}

三、繼承

當多個結構體存在相同的屬性和方法時可以從這些結構體中抽象出結構體,在該結構體中定義這些相同的屬性和方法,其它的結構體中不需要重新定義這些屬性和方法,只需要嵌入一個匿名結構體即可。

也就是說,在golang中如果一個struct嵌套了另一個匿名結構體,那個這個struct可以直接訪問這個匿名結構的屬性和方法,從而實現了繼承特性。

繼承的優點:

1、提高程式碼的復用性和擴展性;

package main
import (
    "fmt"
)

type Animal struct{
    Age int
    Weight float32
}

func (an *Animal) Shout(){
    fmt.Println("我可以大聲喊叫")
}

func (an *Animal) ShowInfo(){
    fmt.Println("動物的年齡是:%v,動物的體重是:%v", an.Age, an.Weight)
}

type Cat struct{
    Animal
}

func (c *Cat) scratch(){
    fmt.Println("我是小貓,我可以撓人。")
}

func main(){
    cat := &Cat{}
    cat.Animal.Age = 3
    cat.Animal.Weight = 10.6
    cat.Animal.Shout()
    cat.Animal.ShowInfo()
    cat.scratch()
}

注意事項:

1、結構體可以使用嵌套匿名結構體所有的欄位和方法,即:首字母大寫和小寫的欄位、方法都可以使用;

2、匿名結構體欄位訪問可以簡化;

3、當結構體和匿名結構體有相同的欄位和方法時,編譯器採用就近訪問原則進行訪問,如果希望訪問匿名結構體屬性和方法,可以通過匿名結構體名來區分;

4、golang中支援多繼承;

package main
import (
    "fmt"
)

type A struct{
    a1 string
    a2 int
}

type B struct{
    b1 string
    b2 int
}

type C struct{
    A
    B
}

func main(){
    c := C{A{"a1", 10}, B{"b1", 20}}
    fmt.Println(c)
}

5、如果嵌入的匿名結構體有相同的屬性名或方法,則在訪問時需要通過匿名結構體類型名來區分;

6、結構體的匿名欄位可以是基本數據類型;

package main
import (
    "fmt"
)

type A struct{
    a1 string
    a2 int
}

type B struct{
    b1 string
    b2 int
}

type C struct{
    A
    B
    int
}

func main(){
    c := C{A{"a1", 10}, B{"b1", 20}, 888}
    fmt.Println(c.a1)
    fmt.Println(c.a2)
    fmt.Println(c.b1)
    fmt.Println(c.b2)
    fmt.Println(c.A.a1)
    fmt.Println(c.A.a2)
    fmt.Println(c.B.b1)
    fmt.Println(c.B.b2)
    fmt.Println(c.int)
}

//a1
//10
//b1
//20
//a1
//10
//b1
//20
//888

7、嵌套匿名結構體後,可以在創建結構體變數時直接指定各個匿名結構體欄位的值;

8、嵌入匿名結構體的指針也是可以的;

9、結構體的欄位可以是結構體類型的。

package main
import (
    "fmt"
)

type A struct{
    a1 string
    a2 int
}

type B struct{
    b1 string
    b2 int
}

type C struct{
    A
    B
    int
}

type D struct{
    a int
    b B
}

func main(){
    d := D{11, B{"BB", 66}}
    fmt.Println(d)
    fmt.Println(d.b.b1)
}

// {11 {BB 66}}
// BB

 

Exit mobile version