"有趣"的go代码案例
目录
一些不好的案例
case1:Jalang
config.go
package config
var CONFIG *config
type config struct {
Host string
Port string
}
func GetHost() string {
return CONFIG.Host
}
func GetPort() string {
return CONFIG.Port
}
main.go
func main() {
// ... init config
engine := gin.Default()
engine.RunListener(config.GetHost()+":"+config.GetPort())
}
理解
猜测原代码是想保护原配置不被其他地方更改,可以直接把config.go里面的
var CONFIG *config
变为私有,如果没有保护配置要求,实际上可以直接 config.CONFIG.Host+":"+config.CONFIG.Post
。case2:消失的const
utils.go
func IsOver(size int) bool{
if size > 10 {
return true
}
return false
}
use.go
if (IsOver(2)) {
return
}
理解
原代码中IsOver被多处调用,可能原编码人想着抽出来,但我感觉这里没必要单写一个函数,直接
const defaultSize = 10
,然后if size>defaultSize {return}
,这样可以增加可阅读性,第三个人读代码时就不必在进行一次跳转。case3:不一定要判空
func Deal(items []string) {
if items == nil {
return
}
for _,item := items {
....
}
}
理解
当切片为nil的时候,无论是对其进行for循环还是取长度都不会panic。
case4: 如果有如果
func If1(a *int) {
if a == nil {
return
}
if a > 10 {
...
}
...
}
理解
两个if可以合并
func If1(a *int) {
if a != nil && a > 10 {
...
}
...
}
case5: 大概率是多余的
log.go
package logger
var Log *logger
type Logger struct {l log}
func InitLogger() {
Log = &logger{l: log.NewLog()}
}
func (l *logger) Info(content string,args ...interface) {
....
}
func (l *logger) Error(content string,args ...interface) {
....
}
use.go
func main() {
logger.Logger.Info("hello")
}
理解
可以简化,使用的时候做到像如下:
logger.Info("hello")
如何优雅地写go
隐式实现
golang的接口都是隐式实现的,如果某个A接口中的方法在B接口存在,那么实现了B接口的方法也会间接实现A接口,这会降低我们的代码可读性。
type Person interface {
GetName() string
GetAge() int
GetHeight() int
}
type Animal interface {
GetName() string
GetAge() int
}
type Chinese struct {
}
func (c *Chinese) GetName() string {
return "zhang"
}
func (c *Chinese) GetAge() int {
return 16
}
func (c *Chinese) GetHeight() int {
return 180
}
当我只想实现Person接口的时候,由于隐式实现的规则,Animal也被实现了,如下图:
可以加一些特殊的方法,如下代码中的两个接口,可以加一些特殊方法区分(此场景建立在后续会对这两个接口调整的情况,要是没有后续修改计划,实际上这两个接口可以合并)
type Person interface {
Person()
GetName() string
GetAge() int
GetHeight() int
}
type Animal interface {
Animal()
GetName() string
GetAge() int
}
如果不想在接口中增加特殊方法,可以强制定义实现
type Person interface {
Person()
GetName() string
GetAge() int
GetHeight() int
}
type Animal interface {
GetName() string
GetAge() int
}
use.go
var _ Person = &Chinese{}
type Chinses struct {}
func (c *Chinses) GetName() string {
return "zhang"
}
func (c *Chinses) GetAge() int {
return 18
}
这样做的好处是可以找到所有真正实现了该接口的
巧妙利用接口
有些属性,我们可以在接口中定义,比如下面例子的name。
反例:
type Person interface {
Age() int
Height() int
Wish() string
}
type Router struct {
router map[string]Person
}
func NewRouter() *Router {
return &Router{
router: make(map[string]Person),
}
}
func (r *Router) Bind(name string, person Person) {
r.router[name] = person
}
func (r *Router) Run(name string) {
f, ok := r.router[name]
if !ok {
fmt.Println("name not found")
return
}
fmt.Printf("my name is %s\n,%d years old,my wish is %s", name, f.Age(), f.Wish())
}
use.go
func main() {
router := NewRouter()
router.Bind((&Chinese{}).Name(), &Chinese{})
router.Bind((&Russian{}).Name(), &Russian{})
router.Run("zhang")
}
优化:
type Person interface {
Name() string
Age() int
Height() int
Wish() string
}
type Router struct {
router map[string]Person
}
func NewRouter() *Router {
return &Router{
router: make(map[string]Person),
}
}
func (r *Router) Add(person Person) {
r.router[person.Name()] = person
}
func (r *Router) Run(name string) {
f, ok := r.router[name]
if !ok {
fmt.Println("name not found")
return
}
fmt.Printf("my name is %s\n,%d years old,my wish is %s", f.Name(), f.Age(), f.Wish())
}
use.go
func main() {
router := NewRouter()
router.Add(&Chinese{})
router.Add(&Russian{})
router.Run("zhang")
}