Go结构体struct

Struct

Go不支持面向对象,但Go通过定义数据结构的方式,也能实现与类Class的功能

type Mankind struct {
    height int
    hair string
}

定义了人的身高、头发属性,但是还没有人的行为方法

man := Mankind{
    height: 175,
    hair: "short",
}

hair 后的逗号","不能省略,Go会报错,也有利于扩展这个数据结构
man := Mankind{ } 中可以把 Mankind 是一个类,man 是 它的一个实例对象,拥有 height 和 hair 属性
生成一个woman实例

woman := Mankind{
    height: 165,
    hair: "long",
}
// 定义空数据结构
man := Mankind{ }

// 或者,先定义一部分,再赋值
man := Mankind {height: 175}
man.hair = "short"

也可以按位置传参

man := Mankind{175,"short"}

指针

man := Mankind{175,"short"} 表示返回一个数据结构给 man ,可以说 man 是这个数据结构的引用
看一下以下两种赋值方式

man := Mankind{175,"short"}
woman := &Mankind{165,"long"}

区别:赋值给 man 的是 Mankind { } 的实例地址,赋值给 woman 的是一个中间指针,指针保存了指向 Mankind { } 的实例地址

man  —>  Mankind { }
woman  —> Pointer  —>  Mankind { }

Pointer在内存中占用一个长度为一个机器字长的单独数据块,64位机器上一个机器字长是8字节
赋值给woman的这个8字节长度的指针地址,这个指针地址再指向 Mankind { },而man则是直接指向Mankind { }

var p *int      // p 是一个指针
i := 24          // 定义 i
p = &i          // & 使 p 取到 i 的值,即24
* 操作符表示指针指向的底层值
*p 可以读取到 24
*p = 25       //通过指针 p 设置 i 为25
总结: p 是指针,*p 是值

Go函数参数传值

Go函数给参数传递值的时候是以复制的方式进行的
复制传值的方式,如果函数的参数是一个数据结构,将直接复制整个数据结构的副本传递给函数
函数内部无法修改传递给函数的原始数据结构,它修改的只是原始数据结构拷贝后的副本

package main

import ("fmt")

type Mankind struct {
    height int
    hair string
}

func main(){
    man := Mankind{
        height: 175,
        hair: "short",
    }
    add(man)
    fmt.Println(man.height)
}

func add(a Mankind){
    a.height += 10
}

上面的输出仍为175
为了修改man所在的数据结构的值,需要使用引用(指针)的方式传值

package main

import ("fmt")

type Mankind struct {
    height int
    hair string
}

func main(){
    man := &Mankind{
        height: 175,
        hair: "short",
    }
    add(man)
    fmt.Println(man.height)
}

func add(a *Mankind){
    a.height += 10
}

修改传递给函数参数的数据结构,这个参数必须是直接指向这个数据结构
a是一个Animal数据结构的一个实例的引用,所以调用add()的时候,传递给add()中的参数必须是一个Animal数据结构的引用

方法:属于数据结构的函数

可以为数据结构定义属于自己的函数

package main

import ("fmt")

type Mankind struct {
    height int
    hair string
}

func (a *Mankind) add( ){
    a.height += 10
}

func main(){
    man := &Mankind{
        height: 175,
        hair: "short",
    }
    man.add( )
    fmt.Println(man.height)    // 185
}

上面的add()函数定义方式func (a *Mankind) add(){},它所表示的就是定义于数据结构Animal上的函数,就像类的实例方法一样,只要是属于这个数据结构的实例,都能直接调用这个函数,正如man.add()一样

构造器

只要一个函数能够根据数据结构返回这个数据结构的一个实例对象,就可以称之为"构造器"
以下是Animal数据结构的一个构造函数

func newMankind(n string,w int) *Mankind {
    return &Mankind{
        name: n,
        weight: w,
    }
}

以下返回的是非引用类型的数据结构

func newMankind(n string,w int) Mankind {
    return Mankind{
        name: n,
        weight: w,
    }
}

一般上面的方法类型称为工厂方法,就像工厂一样根据模板不断生成产品。但对于创建数据结构的实例来说,一般还是会采用内置的new()方式

new函数

Go没有构造器,但Go还有一个内置的new()函数用于为一个数据结构分配内存。其中new(x)等价于&x{},以下两语句等价

man := new(Mankind)
man := &Mankind{}

赋值方式

# 第一种方式
man := new(Mankind)
man.height = 175
man.weight = 65

# 第二种方式
woman := &Mankind{
    height: 165,
    weight: 45,
}

扩展数据结构字段

前面出现的数据类型比较简单string int等,我们可以构造更复杂的,例如可以是map、array等,还可以是自定义的数据类型(数据结构)

type Mankind struct {
    name   string
    weight int
    father *Mankind
}

其中在此处的*Mankind所表示的数据结构实例很可能是其它的Mankind实例对象

man := &Mankind{
    height: 175,
    weight: 65,
    father: &Mankind{
        height: 176,
        weight: 70,
        father: nil,
    },
}

Composition(组合)

在一个数据结构中嵌套另一个数据结构的行为

package main

import (
    "fmt"
)

type Mankind struct {
    height  int
    weight int
}

type Monkey struct {
    *Mankind                  // 注意此行
    speak string
}

func (a *Mankind) hello() {
    fmt.Println(a.height)
    fmt.Println(a.weight)
    //fmt.Println(a.speak)
}

func main() {
    monkey := &Monkey{
        Mankind: &Mankind{        // 注意此行
            height:   175,
            weight: 65,
        },
        speak: "how are you doing today ?",
    }
    monkey.hello()
}

上面的monkey数据结构中包含了一行*Mankind,表示Mankind的数据结构插入到Monkey的结构中,这就像是一种面向对象的类继承。注意,没有给该字段显式命名,但可以隐式地访问Monkey组合结构中的字段和函数
另外,在构建Monkey实例的时候,必须显式为其指定字段名(尽管数据结构中并没有指定其名称),且字段的名称必须和数据结构的名称完全相同
然后调用属于Mankind数据结构的hello方法,它只能访问Mankind中的属性,所以无法访问speak属性
这种代码共享的方式比面向对象的继承更加健壮

Go中的重载overload

将上面属于Mankind数据结构的hello函数重载为属于Monkey数据结构的hello函数

package main

import (
    "fmt"
)

type Mankind struct {
    height  int
    weight int
}

type Monkey struct {
    *Mankind                  // 注意此行
    speak string
}

func (m *Monkey) hello() {
    fmt.Println(m.height)
    fmt.Println(m.weight)
    fmt.Println(m.speak)
}

func main() {
    monkey := &Monkey{
        Mankind: &Mankind{        // 注意此行
            height:   175,
            weight: 65,
        },
        speak: "how are you doing today ?",
    }
    monkey.hello()
}

猜你喜欢

转载自www.cnblogs.com/guotianbao/p/10528242.html