[go-11]面向对象1

一、介绍

1) Go 支持面向对象编程特性(并非传统的oop)。

2) Go 是基于 struct 来实现 OOP 特性的,struct等同于其他语言的class

3) Go 去掉了传统 OOP 语言的重载、构造函数和析构函数、隐藏的 this 指针等等

4) Go 面向对象的三大特征继承,封装和多态

二、结构体

type 结构体名称 struct {

    field1 type

    field2 type

}

三、创建并实例化结构体

// 结构体
type person struct {
    Name string
    Age int
    Sex int8
}


func main() {
    // 创建方式1  声明-赋值-使用
    var p1 person
    fmt.Println(p1) // { 0 0}

    p1.Name="小明"
    p1.Age=18
    p1.Sex=1
    fmt.Println(p1) // {小明 18 1}
}

四、结构体在内存的布局

fmt.Println(p1) // { 0 0}
p1.Name="小明"
p1.Age=18
p1.Sex=1
fmt.Println(p1) // {小明 18 1}

                                                初始                    赋值之后

                                           Name    ""  ------------>  小明

var p1 person----------->      Age        0  ------------>  18

                                           Sex         0  ------------>   1

五、结构体字段/属性

1) 结构体字段 /属性/ field

2) 字段是结构体的一个组成部分,一般是基本数据类型、数组,也可是引用类型。

3) 字段声明语法同变量

4) 结构体未赋值前,会有默认值

布尔类 false ,数值是 0 ,字符串是 “"。

数组类型的默认值和它的元素类型相关,比如 score [3]int 则为[0, 0, 0]

指针,slice,和 map 的零值都是 nil ,即还没有分配空间。

5)  结构体是值类型。

// 结构体
type Person struct {
    Name   string // 基本类型
    Age    int
    Scores [5]float64 // 数组
    ptr    *int       // 引用类型
    slice  []int
    map1   map[string]string
}


func main() {
    // 定义结构体变量
    var p1 Person
    fmt.Println(p1)
    // 结构体默认值 { 0 [0 0 0 0 0] <nil> [] map[]}
    if p1.ptr == nil {
       fmt.Println("ok1")
    }

    if p1.slice == nil {
       fmt.Println("ok2")
    }

    if p1.map1 == nil {
       fmt.Println("ok3")
    }

    // 使用切片 一定要make
    p1.slice = make([]int, 10)
    p1.slice[0] = 100

    // 使用map 一定要make
    p1.map1 = make(map[string]string)
    p1.map1["key1"] = "tom~"
}

六、创建结构体变量和访问结构体字段

// 结构体

type Person struct {
    Name   string
    Age    int
    Scores [5]float64
    ptr    *int
    slice  []int
    map1   map[string]string
}


func main() {
    // 方式一
    var p1 Person
    p1.Name = "和平"
    fmt.Println(p1) // {和平 0 [0 0 0 0 0] <nil> [] map[]}


    // 方式二
    p2 := Person{Name: "小明", Age: 20}
    fmt.Println(p2) // {小明 20 [0 0 0 0 0] <nil> [] map[]}


    // 方式三
    var p3 *Person = new(Person)
    (*p3).Name = "小红"
    p3.Age = 20
    fmt.Println(p3) // &{小红 20 [0 0 0 0 0] <nil> [] map[]}


    // 方式4
    var p4 *Person = &Person{}
    (*p4).Name = "小猴"
    p4.Age = 18
    fmt.Println(p4) // {小猴 18 [0 0 0 0 0] <nil> [] map[]}
}

1) 第 3 种和第 4 种方式返回的是 结构体指针。

2) 结构体指针访问字段的标准方式应该是:(*结构体指针).字段名 ,比如 (*person).Name = "tom"

3) 但 go 做了一个简化,也支持 结构体指针.字段名, 比如 person.Name = "tom"。更加符合程序员

使用的习惯,go 编译器底层 对 person.Name 做了转化 (*person)

七、struct类型的内存分配机制

八、结构体使用注意

1) 结构体的所有字段在内存中是连续的

2) 结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)

package main
import "fmt"
/**
    结构体之间的转换
  */
type Student struct {
    Age int
}

type Person struct {
    Age int
}

func main() {
     var s Student = Student{10}
     var p Person = Person{ 15}
     s = Student(p)
     fmt.Println(s) // 15
}

3) 结构体进行 type 重新定义(相当于取别名),Golang 认为是新的数据类型,但是相互间可以强转

package main
import "fmt"
/**
    结构体之间的转换
  */

type Student struct {
    Age int
}

type Stu Student

func main() {
     var s1 Student = Student{19}
     var s2 Stu = Stu{19}
     s1 = Student(s2)
     fmt.Println(s1) // 19
     fmt.Println(s2) // 19
}

4) struct 的每个字段上,可以写上一个 tag, 该 tag 可以通过反射机制获取,常见的使用场景就是序列化和反序列化。

type Monster struct{
    Name string `json:"name"` //`json:"name"就是 struct tag
    Age int `json:"age"`
    skill string `json:"skill"`
}


func main() {
    //1.创建一个Monster变量
    monster := Monster{"牛魔王", 500, "芭蕉扇~"}
    //2.将monster变量序列化为json格式字串json.Marshal 函数中使用反射
    jsonstr,err := json.Marshal(monster)
    if err != nil {
        fmt.Println("json 处理错误", err)
    }
    fmt.Println("jsonstr",string(jsonstr))
}

八、方法的声明和调用

type A struct {
    Num int
}


func (a A) test() {
    fmt.Println(a.Num)
}

1) func (a A) test() {} 表示 A 结构体有一方法,方法名为 test

2) (a A) 体现 test 方法是和 A 类型绑定的

// 结构体

type Person struct {
    Name strin
}


// Person绑定方法
func (p Person) test() {
    fmt.Println("test() name=", p.Name) //test() name= 猴子
}


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

1) test 方法和 Person 类型绑定

2) test 方法只能通过 Person 类型的变量来调用,而不能直接调用,也不能使用其它类型变量来调用

3) func (p Person) test() {}... p 表示哪个 Person 变量调用,这个 p 就是它的副本, 这点和函数传参非常相似

九、方法的调用和传参机制原理

1) 调用方法和调用函数是一样的

2) 不一样的地方时,通过变量去调用,并传入变量本身,可以是值传递,也可以是引用传递

十、方法的声明和定义

func (recevier type) methodName(参数列表) (返回值列表){

    方法体

    return 返回值

}

1) 参数列表:表示方法输入

2) recevier type : 表示这个方法和 type 这个类型进行绑定,或者说该方法作用于 type 类型

3) receiver type : type 可以是结构体,也可以其它的自定义类型

4) receiver : 就是 type 类型的一个变量(实例),比如 :Person 结构体 的一个变量(实例)

5) 返回值列表:表示返回的值,可以多个

6) 方法主体:表示为了实现某一功能代码块

7) return 语句不是必须的

十一、方法的注意事项和细节

1) 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式

2) 希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理

3) 方法可以用在自定义类型上,而不仅仅是 struct, 比如 int , float32 等都可以有方法

4)和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。

5) 如果一个类型实现了 String()这个方法,那么 fmt.Println 默认会调用这个变量的 String()进行输出

type Person struct{
    Name string
    Age int
}


func (p *Person) String() string {
    return fmt.Sprintf("Name: %s, Age: %d", p.Name, p.Age)
}


func main(){
    p1 := Person {"小明", 18}
    fmt.Println(&p1) // Name: 小明, Age: 18
}

十二、方法和函数的区别

1) 调用方式不一样

函数:

函数名(实参列表)

方法:

变量.方法名(实参列表)

2) 对于普通函数,指针类型就只能用&调用

3) 对于方法 可以用(&) 也可以直接调用,具体是值传递 还是地址传递看方法的绑定

2)3)参考以下案例,注意一个是以参数形式传入,一个是绑定形式传入

//对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
func teste1(p Person1) {
    fmt.Println(p.Name)
}

func teste2(p *Person1) {
    fmt.Println(p.Name)
}


func(p Person1) teste3() {
    p.Name = "jack"
    fmt.Println("test03()=",p.Name)// jack
}


func(p *Person1)teste4(){
    p.Name = "mary"
    fmt.Println("teste3()=",p.Name)// mary
}


func main(){
    p := Person1{"tom"}
    teste1(p) // 值传递
    teste2(&p) // 地址传递

    fmt.Println("main1=",p.Name) // tom
     (&p).teste3() // 里面 name 改成了 jack
     fmt.Println("main2=",p.Name) // tom
    p.teste3() // 效果一样

    p.teste4() // 里面改成了mary
    fmt.Println("main3=",p.Name) // mary
    (&p).teste4() // 效果一样
    // 方法都能用 p 或者 (&p)调用,具体是值传递还是地址传递,看方法的绑定 带*地址传递  不带值传递
}

十三、创建结构体

type Person struct{
    Name string
    Age int
}


func makeStruct() {
    // 1 声明使用
    var p Person
    p.Name = "小唐"
    fmt.Println(p) // {小唐 0}

    // 2 直接赋值
    p1 := Person{"小猴", 18}
    fmt.Println(p1) // {小猴 18}

    // 3 直接赋值②
    p2 := Person{
        Name: "Alice",
    }
    fmt.Println(p2) // {Alice 0}

    // 4 new一个
    p3 := new(Person)
    p3.Name = "Bob"
    p3.Age = 25
    fmt.Println(p3) // Name: Bob, Age: 25
    fmt.Println(*p3) // {Bob 25}

    // 5 &方式
    p4 := &Person{
        Name: "Charlie",
        Age:  35,
    }
    fmt.Println(p4) // Name: Charlie, Age: 35
    fmt.Println(*p4) // {Charlie 35}

    // 6 工厂
    p5 := NewPerson("David", 40)
    fmt.Println(p5) // {David 40}

    p6 := NewPerson2("Eve", 28)
    fmt.Println(*p6) // {Eve 28}
}



func NewPerson(name string, age int) Person {
    return Person{
        Name: name,
        Age:  age,
    }
}


func NewPerson2(name string, age int) *Person {
    return &Person{
        Name: name,
        Age:  age,
    }
}

十四、工厂方法


type Person struct{
    Name string
    Age int
}


func NewPerson(name string, age int) Person {
    return Person{
        Name: name,
        Age:  age,
    }
}


func NewPerson2(name string, age int) *Person {
    return &Person{
        Name: name,
        Age:  age,
    }
}

func makeStruct() {
    // 6 工厂
    p5 := NewPerson("David", 40)
    fmt.Println(p5) // {David 40}
    p6 := NewPerson2("Eve", 28)
    fmt.Println(*p6) // {Eve 28}
}

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值