type定义和Server抽象| 青训营笔记

115 阅读4分钟

HTTP库

request概览

  • Body和GetBody Body: 只能调用一次; 再次读取, 啥也读不到, 但也不会报错 GetBody: 原则上可以多次读取, 但是在原生的http.Request里面, 这个是nil 在读取到body之后, 我们就可以用于反序列化, 比如说把json格式的字符串转换为一个对象等
  • Query 除了Body, 我们还可能传递参数的地方是Query 也就是通过values := r.URL.Query() 获取请求参数

Query也可能出数组的 所有的值都被解释为字符串, 所以需要自己解析为数字等

  • Request URL URL里的Host不一定有值 r.Host一般都有值, 是Host这个header的值 RawPath也不一定有 Path肯定有
  • Method
  • Request Header header大体上是两类, 一类是http预定义的; 一类是自己定义的 Go会自动将header名字转为标准名字 -- 其实就是大小写调整 一般用X开头来表明自己定义的, 比如说 X-mycompany-your=header
  • Form Form和PasrseForm 要先调用ParseForm 建议加上 Content-Type: application/x-www-form-urlencoded
  • ...
// map[key]value
// 这里就是定义了一个map
// map的key是string
// map的value是[]string, string的切片
type Values map[string][]string

要点总结

  • Body和GetBody 重点在于Body是一次性的, 而GetBody默认情况下是没有, 一般中间件会注入这个方法
  • URL 注意URL里面的字段的含义坑并不如你期望的那样
  • Form 记得调用前先用ParseForm, 别忘了请求头里面记上http头

基础语法 type

type定义

  • type 名字 interface {} 里面只能有方法, 方法也不需要有func关键字 接口是一组行为的抽象 尽量用接口, 以实现面向接口编程
type Server interface {
	Route(pattern string, handler http.HandlerFUnc)
	Start(address string) error
}
  • type 名字 struct {} 结构体和结构体的字段都遵循大小写控制访问性的原则
type Name struct {
	fieldName FieldType
	// ...
}
  • type 名字 别的类型
  • type 别名 = 别的类型

结构体初始化

  • Go没有构造函数
  • 初始化语法 Struct{}
  • 获取指针: &Struct{}
  • 获取指针2: new(Struct)
  • new可以理解为Go会为你的变量分配内存, 并且把内存都置为0
// duck1 是 *ToyDuck
duck1 := &ToyDuck{}
duck1.Swim()

duck2 := ToyDuck{}
duck2.Swim()

// duck3 你 *ToyDuck
duck3 := new(ToyDuck)
duck3.Swim()

// 当你声明成这样的时候, Go回帮你分配好内存
// 不用担心空指针的问题, 因为它压根就不是指针
var duck4 ToyDuck
duck4.Swim()

// duck5 就是一个指针, 不会帮助分配内存
var duck5 *ToyDuck
// 直接回panic 
duck5.Swim()

// 赋值, 初始化按字段名字赋值
duck6 := ToyDuck{
	Color: "黄色",
	Price: 100
}

// 赋值, 按字段顺序赋值
duck7 := ToyDuck{"蓝色", 1024}
duck7.Swim()

// 后赋值
duck8 := ToyDuck{}
duck8.Color: "橘色"

指针与方法接收器

和C, C++一样, *表示指针, &取地址 如果声明了一个指针, 但没有被复制, 那么他就是nil

结构体自引用

结构体内部引用自己, 只能使用指针 准确来说, 在整个引用链上, 如果构成循环, 那就只能用指针

type Node struct {
	// 不合法, 因为在创建的时候需要计算大小
	// left Node
	// right Node 
	left *Node
	right *Node
}

方法接收器

type User struct {
	Name string
	Age int
}

// 结构体接收器
func(u User) ChangeName(newName string) {
	u.Name = newName
}

// 指针接收器
func(u *User) ChangeAge(newAge int) {
	u.Age = newAge
}

u1 := User {"Tom", 10}
// 不会改变
u1.ChangeName("newTom")
// 会改变
u1.ChangeAge(11)

u2 := &User {"Tom", 10}
// 不会改变
u2.ChangeName("newTom")
// 胡改变
u2.ChangeAge(11)

// 只有指针接收器可以改变struct
// 遇事不决用指针

结构体如何实现接口

当看到一直鸟走路像鸭子, 游泳像鸭子, 叫起来也像鸭子, 那么这只鸟就可以被称为鸭子.

当一个结构体具备接口的所有的方法时, 它就实现了这个接口.(并不需要引入接口所在的包)

type Server interface {
  Route(pattern string, handleFunc http.HandlerFunc)
  Start(address string) error
}

type sdkHttpServer struct {
  Name string
}

func(s *sdkHttpServer) Route(pattern string, handleFUnc http.HandlerFunc) {
  panic("implement me")
}

func(s *sdkHttpServer) Start(address string) error {
  panic("implement me")
}

最好现有抽象, 再有实现, 所以要先定义接口

Server与Context抽象

context保存用户http请求的上下文, request, response, 等

func (c *Context) OkJson(resp interface{}) error {
	return c.WriteJson(http.StatusOK, resp)
}

做了一层封装 空接口interface{} 类似Object, 是所有对象的基类; 任何结构体都实现了该接口

json库

  • 用于处理json格式字符串
  • 字段后面的内容被称为Tag, 即标签, 运行期间可以反射拿到
  • json根据json Tag来完成json到结构体的映射
  • 典型的声明式API设计
type signUpReq struct {
  // Tag
  Email string `json:"email"`
  Password string `json:"password"`
  ConfirmedPassword string `json:"confirmed_password"`
}

HTTP server -- 进一步封装

  • 提供辅助方法
  • 不是Context本身必须提供的方法.