Golang中的鸭子类型、接口和大胆地面向对象| 青训营笔记

171 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记

面向对象

  • Go语言仅支持封装,不支持继承和多态
  • Go语言没有class,只有struct
  • 不管指针还是实例,都是一路.下去,而不是->

结构的创建

 func createNode(value int) *treeNode { //工厂函数
     return &treeNode{value: value}
 }
 ​
 root.left.right = createNode(2)
  • 使用自定义工厂函数
  • 注意返回了局部变量的地址!

结构创建在堆上还是栈上?

不需要知道。有垃圾回收机制

显示定义和命名方法接收者

 func (node TreeNode) print() {
     fmt.Println(node.value)
 }

使用指针作为方法接收者

 func (node *TreeNode) setValue(value int) {
     node.value = value
 }
  • 只有使用指针才可以改变结构内容,否则是值传递
  • nil指针也可以调用方法

值接收者 VS. 指针接收者

  • 要改变内容必须使用指针接收者
  • 结构过大考虑使用指针接收者
  • 一致性:如有指针接收者,最好都是指针接收者
  • 值接收者是 Go语言特有
  • 值/指针接收者均可接受 值/指针

封装

  • 名字一般使用CamelCase
  • 首字母大写:public
  • 首字母小写:private

  • 每个目录一个包
  • main包比较特殊,有一个可执行的入口
  • 为结构定义的方法必须放在同一个包内
  • 可以是不同文件

如何扩充系统类型或者别人的类型

  • 定义别名:最简单
  • 使用组合:最常用
  • 使用内嵌Embedding:需要省下许多代码(Go语言特殊性)

依赖管理

  • 依赖管理
  • 依赖管理的三个阶段GOPATH,GOVENDOR,go mod

注意:GOPATH下必须创建src文件夹,若找不到包,从GOROOT和GOPATH去找

创建vendor文件夹解决版本不同的问题,先从vendor文件夹去找

vendor -> GOROOT -> GOPATH

第三方依赖管理工具:dep 、glide

glide.yaml

Go mod使用

go get -u

go build ./... 从import里直接go mod

go mod init name

含有main函数的文件必须放在自己单独的一个文件夹里。

接口

动态语言 & 静态语言 -> 类型

 package main
 ​
 import (
     "chapter2/infra"
     "fmt"
 )
 ​
 func getRetriever() retriever {
     return infra.Retriever{}
 }
 ​
 //?: Something that Can "Get"
 type retriever interface {
     Get(string) string
 }
 ​
 func main() {
     var r retriever = getRetriever()
     fmt.Println(r.Get("https://www.imooc.com"))
 }
 ​

duck typing

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

  • 描述事物的外部行为而非内部结构
  • 严格说Go属于结构化类型系统,类似duck typing
 //C++中的duck typing
 template <class R>
 string download(const R& retriever) {
 return retriever.get("www.baidu.com")
 }

接口的定义

使用者 ————> 实现者

downloader retriever

  • 接口由使用者定义
  • 接口的实现是隐式的,只要实现接口里的方法

接口变量里面有实现者的类型,也有指针和值

接口的值类型:类型和值

类型和值可以用swithc打印出来

也可以用Type assertion

 package main
 ​
 import (
     "chapter2/retriever/mock"
     "chapter2/retriever/real"
     "fmt"
     "time"
 )
 ​
 type Retriever interface {
     Get(url string) string
 }
 ​
 func download(r Retriever) string {
     return r.Get("https://www.imooc.com")
 }
 ​
 func main() {
     var r Retriever
     r = mock.Retriever{"this is a fake imooc.com"}
     inspect(r)
 ​
     r = &real.Retriever{
         UserAgent: "Mozila/5.0",
         TimeOut:   time.Minute,
     }
     inspect(r)
 ​
     //Type assertion
     realRetriever := r.(*real.Retriever)
     fmt.Println(realRetriever.TimeOut)
 ​
     //fmt.Println(download(r))
 ​
 }
 ​
 func inspect(r Retriever) {
     fmt.Printf("%T %v\n", r, r)
     switch v := r.(type) {
     case mock.Retriever:
         fmt.Println("Contents: ", v.Contents)
     case *real.Retriever:
         fmt.Println("UserAgent: ", v.UserAgent)
     }
 ​
 }
 ​

查看接口变量

  • 表示任何类型:interface{}
  • Type Assertion
  • Type Switch

接口的组合

 type ReaderWriter interface {
     Reader
     Writer
 }

常用系统接口

Stringer

Reader/Writer