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