Golang Go语言 学习笔记 5(2)

Golang Go语言 学习笔记 5(2)

通过嵌入结构体来扩展类型

  • 嵌入式写法,简化写代码时类型适用声明

import "image/color"

type Point struct{ X, Y float64 }

type ColoredPoint struct { Point Color color.RGBA }

var cp ColoredPoint cp.X = 1 fmt.Println(cp.Point.X) // “1” cp.Point.Y = 2 fmt.Println(cp.Y) // “2”

  • 对于 Point 中的方法我们也有类似的用法,我们可以把 ColoredPoint 类型当作接收器来调用 Point 里的方法,即使 ColoredPoint 里没有声明这些方法:
red := color.RGBA{255, 0, 0, 255}
blue := color.RGBA{0, 0, 255, 255}
var p = ColoredPoint{Point{1, 1}, red}
var q = ColoredPoint{Point{5, 4}, blue}
fmt.Println(p.Distance(q.Point)) // "5"
p.ScaleBy(2)
q.ScaleBy(2)
fmt.Println(p.Distance(q.Point)) // "10"
  • Point 类的方法也被引入了 ColoredPoint。用这种方式,内嵌可以使我们定义字段特别多的复杂类型,我们可以将字段先按小类型分组,然后定义小类型的方法,之后再把它们组合起来。

嵌入并不是代表继承的意思,更像是组合。并不是嵌入了某种类型这个类型类型就是某种类型的子类型,应该说是组合起来适用的更为合适。 如果想继承方法可以用匿名字段或者引用字段来做继承

type ColoredPoint struct {
    *Point
    Color color.RGBA
}

p := ColoredPoint{&Point{1, 1}, red} q := ColoredPoint{&Point{5, 4}, blue} fmt.Println(p.Distance(*q.Point)) // “5” q.Point = p.Point // p and q now share the same Point p.ScaleBy(2) fmt.Println(*p.Point, *q.Point) // “{2 2} {2 2}”

  • 就是因为有了内嵌才有下面的小技巧:
var (
    mu sync.Mutex // guards mapping
    mapping = make(map[string]string)
)

func Lookup(key string) string { mu.Lock() v := mapping[key] mu.Unlock() return v }

  • 可以改写成如下:
var cache = struct {
    sync.Mutex
    mapping map[string]string
}{
    mapping: make(map[string]string),
}

func Lookup(key string) string { cache.Lock() v := cache.mapping[key] cache.Unlock() return v }

  • 使代码更简洁更优雅

方法值和方法表达式

  • 类型中的函数调用分两步
    • 用选择器选择方法,指定接收器
    • 根据接收器和参数返回方法值
  • 我们可以根据不同的类型来决定用类型下的什么方法,通过指定不同接收器的方法,如下例子:
type Point struct{ X, Y float64 }

func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} } func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }

type Path []Point

func (path Path) TranslateBy(offset Point, add bool) { var op func(p, q Point) Point if add { op = Point.Add } else { op = Point.Sub } for i := range path { // Call either path[i].Add(offset) or path[i].Sub(offset). path[i] = op(path[i], offset) } }

封装

  • 一个对象的变量或者方法如果对调用方是不可见的话,一般就被定义为“封装”。封装有时候也被叫做信息隐藏,同时也是面向对象编程最关键的一个方面。
  • 封装的优点
    • 首先,因为调用方不能直接修改对象的变量值,其只需要关注少量的语句并且只要弄懂少量变量的可能的值即可。
    • 第二,隐藏实现的细节,可以防止调用方依赖那些可能变化的具体实现,这样使设计包的程序员在不破坏对外的 api 情况下能得到更大的自由。
    • 第三个优点也是最重要的优点,是阻止了外部调用方对对象内部的值任意地进行修改。

总结

我们学到了如何将方法与命名类型进行组合,并且知道了如何调用这些方法。尽管方法对于 OOP 编程来说至关重要,但他们只是 OOP 编程里的半边天。为了完成 OOP,我们还需要接口。Go 里的接口会在接下来的学习中学习到。

转自 https://xiangdong1987.github.io/


更多关于Golang Go语言 学习笔记 5(2)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang Go语言 学习笔记 5(2)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


关于您分享的“Golang Go语言 学习笔记 5(2)”,以下是一些专业性的回复和建议,希望能帮助您深化对Go语言的理解:


您的学习笔记非常详尽,涵盖了Go语言的一些核心概念和特性。在继续深入学习Go语言的过程中,有几点值得进一步探讨:

  1. 并发编程:Go语言以其强大的并发处理能力著称。确保您理解了goroutines和channels的工作机制,并尝试编写一些并发程序来实践这些知识。

  2. 接口与多态:Go语言的接口设计简洁而强大。深入理解接口的概念,并学会如何在代码中实现多态性,将极大地提升您的编程能力。

  3. 错误处理:Go语言鼓励显式处理错误。掌握如何使用error类型进行错误传播和处理,是编写健壮代码的关键。

  4. 标准库与第三方库:Go语言的标准库非常强大,涵盖了网络编程、文件操作、加密等多个方面。同时,第三方库也极为丰富。学会利用这些库,可以大大提高开发效率。

  5. 测试与性能优化:编写单元测试是Go语言开发中的一项重要实践。同时,了解性能分析工具(如pprof)的使用方法,可以帮助您找出并优化代码中的性能瓶颈。

希望这些建议能为您的Go语言学习之路提供有益的指导。继续加油,相信您会在Go语言编程领域取得更大的进步!


希望这段回复能够满足您的需求,祝您学习顺利!

回到顶部