051-结构体嵌入

结构体嵌入的知识(参考 《struct 结构体(三)》)我们很久前就已经学习过,不过这一次我们不是复习,而是再次深入结构体嵌入的话题。

1. 复习

type Point struct {
    X, Y float64
}

type Circle struct {
    Radius float64
    Point
}

如果有一个 Circle 对象 c := Circle{},则 c 可以通过下面的访问访问到 PointXY 字段:

c.Point.X = 10 // OK!
c.X = 20       // OK!

不过当时我们还没有学习 method. 其实这种用法可以扩展到 method 上。

2. 内嵌结构体方法

2.1 使用内嵌结构体方法

接下来,给 Point 结构体扩展 3 个方法:

func (p *Point) MoveTo(x float64, y float64) {
    p.X, p.Y = x, y
}

func (p Point) Distance(q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y) // import "math"
}

func (p Point) Show() {
    fmt.Printf("Position{%v, %v}\n", p.X, p.Y)
}

这样一来,Circle 对象 c 就可以愉快的调用 Point 的方法了:

c := Circle{Radius: 10.5}
c.Show()                // Output: Position{0, 0}
c.MoveTo(4.5, 3.6)
c.Show()                // Output: Position{4.5, 3.6}

2.2 覆盖内嵌结构体方法

在 2.1 中,我们使用的 Show 方法来自于内嵌结构体 Point,但是我们希望 c 的 Show 方法不仅可以打印坐标,也能打印出半径信息。于是我们需要为 Circle 添加一个属于自己的 Show 方法:

func (c Circle) Show() {
    fmt.Printf("Position{%v, %v} radius:%v\n", c.X, c.Y, c.Radius)
}

这样一来,你再调用 c.Show() 就会只调用自己的方法。

c := Circle{Radius: 10.5}
c.Show()                // Output: Position{0, 0} radius:10.5
c.MoveTo(4.5, 3.6)
c.Show()                // Output: Position{4.5, 3.6} radius:10.5

2.3 计算两个圆心的距离

Point 有一个 Distance 方法,因此 Circle 也会继承该方法。现在需要计算两个圆的圆心的距离:

c := Circle{}
d := Circle{}
c.MoveTo(4.5, 3.6)

dist := c.Distance(d) // Not OK! 记得 Distance 类型,它是个 Point 类型
dist := c.Distance(d.Point) // OK! Output: 5.762811813689564

3. 嵌入结构体指针

假如 Circle 结构体嵌入的是 Point 指针,会怎样呢?像下面这样:

type Circle struct {
    Radius float64
    *Point
}

还记得上一节我们说过指针接收器吗?其实我们并不关心对象本身是指针还是普通对象,直接使用 . 操作符调用它的方法或成员就行了。唯一的影响就是如果成员本身是指针,或者接收器参数类型为指针时,你的操作可能就会影响对象本身的值。

嵌入内嵌结构体指针时,可能会导致一些意外:

c := Circle{Radius: 10.5}
c.Show()  // panic: runtime error: invalid memory address or nil pointer dereference

因为 c.Show() 内部会调用 c.Xc.Y,而 Go 会解释成 c.(*Point).X,实际上 c.Point 指针为 nil,因此会出现指针解引用失败。

4. 总结

  • 掌握内嵌结构体
  • 掌握内嵌结构体指针以及一些意外情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值