go面向对象(结构体)

结构体

  • 一个程序就是一个世界,有很多对象(变量)


  • 思路
    1、用变量解决
    2、用数组解决

使用变量和数组来解决不利于数据的维护。所以引出用结构体来抽象猫的特性。

Golang语言面向对象编程说明

1、golang也支持面向对象(OOP),但是和传统的面向对象编程有区别。并不是纯粹的面向对象。应该说。Golang支持面向对象特性。
2、Golang没有类(class),Go语言的结构体(struct)和其它语方的类(class)有同等的地位,你可以理解Golang是基于struct来实现OOP特性。
3、Golang面向对象非常简洁,去掉了传统OOP语言的继承,方法重载,构造函数,析构函数、隐藏的this指针
4、Golang仍然有面向对象编程的继承,封装和多态特性。只是实现的方式和其它不一样。比如继承:Golang没有extends关键字,继承是通过匿名字段来实现的。
5、Golang面向对象(OOP)很优雅。OOP本身就是语方类型(type stystem)的一部分。通过接口(interface)关联。耦合性低,Golang中面向接口编程是非常重要的特性。

对上图的说明
1、将一类事物的特性提取出来(比如猫类),形成一个新的数据类型(结构体)。
2、通过结构体,可以创建多个变量(实例)
3、事物可以猫类,人类,或某个工具类。

  • 快速入门解决(面向对象解决养猫的问题)
//定义结构体
type Cat struct {
    Name  string //""
    Age   int    // 0
    Color string // ""
    Hobby string
}

func main() {
    //创建一个cat的变量
    var cat1 Cat
    fmt.Println(cat1)
    cat1.Name = "小白"
    cat1.Age = 3
    cat1.Color = "白色"
    cat1.Hobby = "吃鱼 <*(((()->"
    fmt.Println(cat1)
    fmt.Println("猫名:", cat1.Name)
    fmt.Println("猫年龄:", cat1.Age)
    fmt.Println("猫颜色:", cat1.Color)
    fmt.Println("猫喜欢:", cat1.Hobby)
}

通过上面案例可以看出
1、结构体是自定义的数据类型,代表一类事物
2、结构体变量(实例)是具体的,实际的,代表一个具体变量。

结构体变量在内存中的布局。

结构体声明

type 结构体名称 struct {
    字段  字段类型
    Age   int    // 0
    Color string // ""
    Hobby string
//首字母大写是公有的,可以被其它包使用
}

字段/属性注意及说明

1、字段声明语法同变量,字段名 字段类型
2、字段的类型可为:基本类型、数组或引用类型
3、在创建一个结构体充数量后。如果没有赋值,都对应一个零值

布尔类型是false,数值是0,字符串是""
数组类型的默认值和它的元素类型相关,比如 scope [3]int 默认值 是[0,0,0]
指针,slice,和map的零值是nil,即还没有分配内存空间

//定义结构体
type Person struct {
    Name   string //""
    Age    int    // 0
    Scores [5]float64
    Ptr    *int              //指针
    Slice  []int             //切片
    Map1   map[string]string //map

}
func main() {
    //定义结构体变量
    var p1 Person
    fmt.Println(p1)
    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
    fmt.Println(p1)

    p1.Map1 = make(map[string]string)
    p1.Map1["key1"] = "tom~~"
    fmt.Println(p1)
}

4、不同结构体的变量的字段是独立的,互不影响。

//定义结构体
type Monster struct {
    Name string
    Age  int
}

func main() {
    //定义结构体变量
    var monster1 Monster
    monster1.Name = "牛魔王"
    monster1.Age = 500

    monster2 := monster1 //默认结构体是值类型,默认为值拷贝
    monster2.Name = "青牛精"
    fmt.Println("monster1=", monster1)
    fmt.Println("monster2=", monster2)
}

上面代码的内存示意图


创建结构体变量和访问结构体字段 4种方式

1、方式1- 直接声明

//案例:
var person Person

2、方式2- { }

//定义结构体
type Monster struct {
    Name string
    Age  int
}

func main() {
    //定义结构体变量
    p2 := Monster{"mary", 20}
    //p2.Name = "tom"
    fmt.Println(p2)
}

3、方式3 - 通过new

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    //方式3
    var p3 *Person = new(Person)
    //因为祝p3是一个指针,标准方式是
    //(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"
    //为了方便使用,会在底层做了处理
    //会给 p3加上 取值运算  (*p3).Name = "smith"
    (*p3).Name = "smith"
    p3.Name = "john"
    (*p3).Age = 30
    p3.Age = 99
    fmt.Println(*p3)
}

4、方式4 - &{ }

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    //方式3
    var p3 *Person = new(Person)
    //因为祝p3是一个指针,标准方式是
    //(*p3).Name = "smith" 也可以这样写 p3.Name = "smith"
    //为了方便使用,会在底层做了处理
    //会给 p3加上 取值运算  (*p3).Name = "smith"
    (*p3).Name = "smith"
    p3.Name = "john"
    (*p3).Age = 30
    p3.Age = 99
    fmt.Println(*p3)

    //方式4 - &name{}
    var person *Person = &Person{}
    //创建的时候赋值
    //var person *Person = &Person{"mary",60}

    //因为person是一个指针,因此标准的用法是
    //(*person).Name = "scott"
    //但是为了简化,go的设计者为了程序员方便,也可以直接这样用
    //person.Name = "scott"
    (*person).Name = "scott"
    person.Name = "scott~~~"
    (*person).Age = 88
    person.Age = 111

    fmt.Println(*person)
}

说明:

1、第3种和第4种方式返回的都是结构体的指针
2、结构体指针访问字段的标准方式是 结构体指针.字段名,比如:
(*person).Name = "tom"
3、但是go做了简化,它也支持 结构体名.字段名,因为go在编译器层做了转化处理。

struct类型的内存分配机制

  • 变量总是存在内存中的。

结构体的变量在内存中是如何存在的,看下面图示

//定义结构体
type Person struct {
    Name string
    Age  int
}

func main() {
    var p1 Person
    p1.Age = 10
    p1.Name = "小明"

    var p2 *Person = &p1

    fmt.Println((*p2).Age)
    fmt.Println(p2.Age)

    p2.Name = "tom~"
    fmt.Printf("p2.Name = %v p1.Name = %v \n", p2.Name, p1.Name)
    fmt.Printf("p2.Name = %v p1.Name = %v \n", (*p2).Name, p1.Name)

    fmt.Printf("p1的地址:%p\n", &p1)

    fmt.Printf("p2的值为:%p\n", p2)
    fmt.Printf("p2的地址:%p\n", &p2)
}

注意

fmt.Println(*p2.Age) 写法会报错。原因是:.的优先级比*高,
所以用()括起来。()优先级大于.

你可能感兴趣的:(go面向对象(结构体))