Golang 编程思维和工程实战
发布于 2021-11-04 15:16 ,所属分类:软件编程学习资料
一 Golang 编程思维
首先,我们先来看下最基本的,就是 Golang 的学习技巧,比如: 通读 Golang 的一些好的文章如Frequently Asked Questions (FAQ)或者看看FAQ 的中文翻译,主要是了解 Golang 的全貌。 Go 精华文章列表 Go 相关博客列表 Go Talks 项目基本架构的组织 代码基本的编码封装 代码的基本原则规范 并发的设计思想 面向对象编程的设计思想 可扩展性的设计思想 然后就是实践,实实在在的跑一些代码示例,可以自己建立一个 base-code 的项目,里面就是你的各种示例,然后进行一些修改、执行。 Go 101 其次,要理解 Golang 编程思维,首先要理解 Golang 这门语言的创始初衷,初衷就是为了解决好 Google 内部大规模高并发服务的问题,主要核心就是围绕高并发来开展;并且同时又不想引入面向对象那种很复杂的继承关系。 首先,就是可以方便的解决好并发问题(包括高并发),那么就需要有并发思维,能够并发处理就通过并发来进行任务分配 这个就是涉及到了 context、 goroutine、channel(select) 可以创建大量 goroutine, 但是需要能通过 context、 channel 建立 "父子"关系,保证子任务可以能够被回收、被主动控制(如 杀死) 再者,面向对象编程思想,利用好 interface、 struct 来实现继承、多态的用法 struct 匿名组合来实现继承 interface 和 struct 来实现多态 interface 定义接口,尽可能的保持里面的方法定义简单,然后多个 interface 进行组合 然后,理解 Golang 语言本身的一些特性: 强类型,语法上要注意处理 GC,实际中要观察 GC 日志并分析 注意语法语义尽可能的简单、保持各种类型定义尽可能精简 最后,从 Golang 社区的一些最佳实践来看,Golang 的各种组件需要尽可能的精简。 Golang 中用好的一些开源组件库,都是比较轻量级的,然后可以各自随意组合来达到最佳实践。 我们自己进行组件封装、模块封装的时候,也是保持这个原则,尽可能的精简,然后使用方进行组合。
二 Golang 高级编码技巧
1 优雅的实现构造函数编程思想
/*
一个更为优雅的构造函数的实现方式
参考:
https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html
通过这个方式可以方便构造不同对象,同时避免了大量重复代码
*/
package main
import (
"fmt"
"time"
"golang.org/x/net/context"
)
type Cluster struct {
opts options
}
type options struct {
connectionTimeout time.Duration
readTimeout time.Duration
writeTimeout time.Duration
logError func(ctx context.Context, err error)
}
// 通过一个选项实现为一个函数指针来达到一个目的:设置选项中的数据的状态
// Golang函数指针的用法
type Option func(c *options)
// 设置某个参数的一个具体实现,用到了闭包的用法。
// 不仅仅只是设置而采用闭包的目的是为了更为优化,更好用,对用户更友好
func LogError(f func(ctx context.Context, err error)) Option {
return func(opts *options) {
opts.logError = f
}
}
// 对关键数据变量的赋值采用一个方法来实现而不是直接设置
func ConnectionTimeout(d time.Duration) Option {
return func(opts *options) {
opts.connectionTimeout = d
}
}
func WriteTimeout(d time.Duration) Option {
return func(opts *options) {
opts.writeTimeout = d
}
}
func ReadTimeout(d time.Duration) Option {
return func(opts *options) {
opts.readTimeout = d
}
}
// 构造函数具体实现,传入相关Option,new一个对象并赋值
// 如果参数很多,也不需要传入很多参数,只需要传入opts ...Option即可
func NewCluster(opts ...Option) *Cluster {
clusterOpts := options{}
for _, opt := range opts {
// 函数指针的赋值调用
opt(&clusterOpts)
}
cluster := new(Cluster)
cluster.opts = clusterOpts
return cluster
}
func main() {
// 前期储备,设定相关参数
commonsOpts := []Option{
ConnectionTimeout(1 * time.Second),
ReadTimeout(2 * time.Second),
WriteTimeout(3 * time.Second),
LogError(func(ctx context.Context, err error) {
}),
}
// 终极操作,构造函数
cluster := NewCluster(commonsOpts...)
// 测试验证
fmt.Println(cluster.opts.connectionTimeout)
fmt.Println(cluster.opts.writeTimeout)
}
type Cluster struct {
opts options
}
func NewCluster(opts ...Option) *Cluster {
....
cluster := new(Cluster)
cluster.opts = clusterOpts
return cluster
}
2 优雅的实现继承编程思想
package main
import (
"fmt"
)
// 【基类】
//定义一个最基础的struct类MsgModel,里面包含一个成员变量msgId
type MsgModel struct {
msgId int
msgType int
}
// MsgModel的一个成员方法,用来设置msgId
func (msg *MsgModel) SetId(msgId int) {
msg.msgId = msgId
}
func (msg *MsgModel) SetType(msgType int) {
msg.msgType = msgType
}
//【子类】
// 再定义一个struct为GroupMsgModel,包含了MsgModel,即组合,但是并没有给定MsgModel任何名字,因此是匿名组合
type GroupMsgModel struct {
MsgModel
// 如果子类也包含一个基类的一样的成员变量,那么通过子类设置和获取得到的变量都是基类的
msgId int
}
func (group *GroupMsgModel) GetId() int {
return group.msgId
}
/*
func (group *GroupMsgModel) SetId(msgId int) {
group.msgId = msgId
}
*/
func main() {
group := &GroupMsgModel{}
group.SetId(123)
group.SetType(1)
fmt.Println("group.msgId =", group.msgId, "\tgroup.MsgModel.msgId =", group.MsgModel.msgId)
fmt.Println("group.msgType =", group.msgType, "\tgroup.MsgModel.msgType =", group.MsgModel.msgType)
}
相关资源