#64 Golang: 泛型
Golang GoGenerics 2021-10-18泛型就是在编码中,涉及类型的定义可以不指定具体的类型,编译器根据使用时的上下文来生成相应类型的定义。
#63 七牛云 Go+
Golang 2021-10-14#62 转载:Diss Golang
Golang 2021-09-06作者可能比较喜欢 C# (C# 的特性你让我丢掉哪一个我都觉得少块肉
), 对 Golang 进行了一些批评,认为其设计缺乏远见,存在很多缺陷:
Anders Hejlsberg 和 Microsoft 把最佳设计都端到眼前了,其他语言纷纷各取所需,但是 Golang 的设计者却不为所动。
#61 Golang 学习资料
Golang 2021-08-24- 官方文档镜像:https://docs.studygolang.com/
- Golang PlayGround: https://play.golang.org/ (自动跳到 https://go.dev/play/)
- https://awesome-go.com/
- https://github.com/avelino/awesome-go
- https://github.com/jobbole/awesome-go-cn 中文版
- Go语言爱好者周刊
- 开源图书
- 《Go 入门指南》
《The Way to Go》中文版 - 《高效的 Go 编程》
《Effective Go》中文版 - 《Go语言标准库》
《The Golang Standard Library by Example》中文版 - 极客兔兔,七天用Go从零实现系列
#60 Golang 定时任务
Golang 2021-08-23time.Ticker
异步执行(需要程序其他部分实现阻塞)
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个每秒触发一次的定时器
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() // 程序结束时停止定时器
// 启动一个 goroutine 执行定时任务
go func() {
for _ = range ticker.C {
// 每次定时器触发时执行任务
fmt.Printf("ticked at %v\n", time.Now())
}
}()
// 让主线程等待,以便定时任务能够执行
// 例如,等待 5 分钟后退出
time.Sleep(5 * time.Minute)
}
同步执行(主线程阻塞)
在主线程内的 for 循环中使用 select 来等待定时器触发。
主线程会一直阻塞在 select 语句中,直到收到定时器的触发信号。
package main
import (
"fmt"
"time"
)
func main() {
// 创建一个每秒触发一次的定时器
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() // 程序结束时停止定时器
// 使用一个无限循环来监听定时器的信号
for {
select {
case <-ticker.C: // 当定时器触发时,执行任务
fmt.Println("执行定时任务:", time.Now())
}
}
}
time.After
package main
import (
"fmt"
"time"
)
func main() {
// 延迟 5 秒后执行任务
select {
case <-time.After(5 * time.Second):
fmt.Println("执行延迟任务:", time.Now())
}
}
time.Sleep
package main
import (
"fmt"
"time"
)
func main() {
// 每隔 3 秒执行一次任务
for {
fmt.Println("执行定时任务:", time.Now())
time.Sleep(3 * time.Second)
}
}
time.AfterFunc
package main
import (
"fmt"
"time"
)
func main() {
// 延迟 3 秒执行任务
time.AfterFunc(3*time.Second, func() {
fmt.Println("延时执行的任务:", time.Now())
})
// 主线程继续运行,避免程序退出
time.Sleep(5 * time.Second)
}
#59 Gin 源码阅读 [编辑中]
Golang Gin 2021-08-17:) 本文正在编辑中,暂时不提供浏览...
#58 Beego 路由
Golang Beego BeegoNotes 2021-08-02基础路由
web.Get(router, web.HandleFunc)
web.Post(router, web.HandleFunc)
web.Put(router, web.HandleFunc)
web.Patch(router, web.HandleFunc)
web.Head(router, web.HandleFunc)
web.Options(router, web.HandleFunc)
web.Delete(router, web.HandleFunc)
web.Any(router, web.HandleFunc)
控制器路由
// func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
// return BeeApp.Router(rootpath, c, mappingMethods...)
// }
beego.Router("/admin", &admin.UserController{})
- 默认匹配
/:id
,/?:id
- 类型匹配
/:id:int
,/:id:string
- 正则匹配
/:id([0-9]+)
- 星号匹配
/username/*
=>:splat
变量
/username/*.*
=>:path
变量和:ext
变量
取变量的方式:
c.Ctx.Input.Param(":id")
mappingMethods
映射 HTTP 方法到指定方法。
- 支持基础路由中提到到八种方法(Any 用星号代替,优先级最低)。
- 如果不指定这个参数,会映射 GET 请求到
Get
方法,以此类推。 - 应该不支持指定多个方法。
- 应该不支持重复指定方法。
web.Router("/api/food",&RestController{},"get:ListFood")
web.Router("/api/food",&RestController{},"post:CreateFood")
web.Router("/api/food",&RestController{},"put:UpdateFood")
web.Router("/api/food",&RestController{},"delete:DeleteFood")
web.Router("/api",&RestController{},"get,post:ApiFunc")
web.Router("/api/food",&RestController{},"get:ListFood;post:CreateFood;put:UpdateFood;delete:DeleteFood")
注意:控制器可以声明 URLMapping 方法,比 mapptingMethods
参数通过反射实现更加高效。
func (c *CMSController) URLMapping() {
c.Mapping("StaticBlock", c.StaticBlock)
c.Mapping("AllBlock", c.AllBlock)
}
自动路由
web.AutoRouter(&controllers.ObjectController{})
URL 采用 /:controller/:method 前缀的方式,后面的部分会转化成 map 参数 (.Ctx.Input.Params
)。
method 不区分大小写,对应的处理方法名首字母大写,比如 login -> Login。
注意:/system/config.json 对应到 SystemController.Config
方法,后缀通过 .Ctx.Input.Param(":ext")
获取。
注解路由
- 2.0 开始支持,dev 模式生效
- 自动扫描指定目录,生成
routers/commentsRouter.go
文件 CommentRouterPath
配置扫描目录
web.Include(&CMSController{})
相应的控制器需要添加这样格式的注解:
// @router /staticblock/:key [get]
#57 Beego 框架: 入门
Golang Beego BeegoNotes 2021-07-07照着官网文档 http://beego.vip 过一遍。
PS: 我之前看的网址是 beego.me, 不知道为啥换了域名。
#56 Golang RabbitMQ
Golang RabbitMQ MQ 2021-06-18- 2014/07/11, RabbitMQ & AMQP
- 2015/02/12, Python RabbitMQ
- 2015/04/01, RabbitMQ 管理命令
- 2015/05/04, pika 01: 基础
- 2015/05/04, pika 02: BlockingConnection
- 2015/05/05, pika 03: SelectConnection
- 2015/05/06, pika 04: TornadoConnection
- 2016/02/12, Java RabbitMQ
- 2018/01/31, RabbitMQ 集群
- 2018/04/01, 面试题:RabbitMQ 相关
- 2018/10/02, pika: AsyncioConnection
- 2018/10/06, 使用 RabbitMQ 遇到的一个小问题
- 2019/01/12, 延迟队列
- 2020/10/03, 常见的消息队列
- 2021/06/18, Golang RabbitMQ
RabbitMQ 是啥就不说了,怎么安装部署也不说了,就记录一下 RabbitMQ 在 Golang 开发中的应用。
说明:采用 github.com/streadway/amqp
库。
func (ch *Channel) Publish(exchange, key string, mandatory, immediate bool, msg Publishing) error
func (ch *Channel) Consume(queue, consumer string, autoAck, exclusive, noLocal, noWait bool, args Table) (<-chan Delivery, error)
生产者
生产者基本流程
生产者:连接
amqp.Dial
->amqp.Connection
amqp.Connection.Channel
->amqp.Channel
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
if err != nil {
log.Fatalf("Failed to connect to RabbitMQ: %s", err)
}
ch, err := conn.Channel()
if err != nil {
log.Fatalf("Failed to open a channel: %s", err)
}
生产者:配置(可选)
事先把 MQ 配好就行,但从稳妥起见,还是在连接时加上比较好。
amqp.Channel.QueueDeclare
amqp.Channel.ExchangeDeclare
amqp.Channel.QueueBind
q, err := ch.QueueDeclare(
"hello", // 队列名称
true, // 持久化
false, // 自动删除
false, // 独占
false, // 等待服务器回应
nil, // 额外参数
)
if err != nil {
log.Fatalf("Failed to declare a queue: %s", err)
}
生产者:发送
amqp.Channel.Publish
err = ch.Publish(
"", // exchange
q.Name, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
Body: []byte("hello world"),
})
if err != nil {
log.Fatalf("Failed to publish a message: %s", err)
}
生产者:收尾
amqp.Connection.Close
amqp.Channel.Close
消费者
消费者基本流程
和生产者基本一致。只是调用的的是 chan.Consume
而不是 chan.Publish
。
然后就是配置阶段,消费者只用关心队列在不在。