前阵子在网上看到一些关于Go比较不错的小知识点,下面总结下分享给你们。面试
new和make都是Go中用来建立对象用的,new这个关键字在不少编程语言里都有,好比在C++和Java里,均可以用new来建立对象。编程
在Go中,new的做用一样是用来建立对象,好比new(T)将会为T建立对象,并同时将这个对象赋一个零值,而后返回T对象的指针*T,下面咱们演示用3种不一样的办法建立bytes.Buffer的对象,并返回它的指针。后端
// 声明一个变量,而后取它的地址并赋值给指针p var buf bytes.Buffer p := &buf // 使用复合声明的方式一步完成 p := &bytes.Buffer{} // 使用new也是一步完成 p := new(bytes.Buffer) 复制代码
上面3种建立对象的方法都是等价的。bash
make在平常的编程中也很经常使用,可是它的使用范围仅限于在slice,map,channel中。使用make也是建立对象,好比make(T),但它返回的是对象的值T,回顾下make的用法。微信
// 建立一个长度为0,容量为8的slice sl := make([]string, 0, 8) // 建立一个阻塞的channel ch := make(chan int) // 建立一个map m := make(map[string]string) 复制代码
上面使用make建立的对象返回的都是对应的值类型。markdown
1. new返回的是T的指针,make返回的是T的值。app
2. make仅能用于建立slice,map,channel。编程语言
对于变量命名,Go大师Dave Cheney举了个颇有趣比喻:你给变量命名就像给你家的宠物取名同样,名字上不要带上“xx狗”,”xx猫“,由于你们都能知道它是狗仍是猫。函数
因此你的变量名应该是描述变量的内容,而不是描述变量的类型,看看如下的写法。oop
var usersMap map[string]*User 复制代码
usersMap这个变量名看起来还不错,描述的是*User的map映射类型。可是Go是一门静态语言,咱们给一个map取变量名的时候是不须要像动态语言同样,由于怕赋值错误的类型而给它加上类型的,所以这个Map后缀是多余的。
咱们再以这种方式来命名几个变量。
var ( companiesMap map[string]*Company productsMap map[string]*Products ) 复制代码
如今,咱们已经命名了3个map类型的变量:usersMap,companiesMap,productsMap ,其中它们对应的value值都是不一样的struct类型。当咱们将*User赋值productsMap的时候,这时候编译器是会报错的,不像动态语言那样只能在运行时才会报错。
这种状况下,加上Map后缀并无更好的描述这个变量,反而还只是一个多余的后缀。因此不建议在变量名中带有类型。
一样的在方法命名上也相似。
type Config struct { // } func (c *Config) WriteConfig(w io.Writer) { // } // would be better func (c *Config) Write(w io.Writer) { // } 复制代码
上面代码中,由于WriteConfig是*Config的方法,因此Config后缀也是多余的。
另外,包名最好别占用类型的名字,就像context包里的Context类型,当咱们引入这个context包的时候,只能用相似ctx这种变量名,而不是context。
// 这样命名就很奇怪,并且十分很差看
func WriteLog(context context.Context, message string)
// 只能以这样的形式取名
func WriteLog(ctx context.Context, message string)
复制代码
Go的变量命名宗旨是简洁明了,变量名应该独立于它的类型。
想象下你写的代码中,使用到的一个函数会panic可能会panic,并且你还改不了那个函数,像这样:
func pressButton() { fmt.Println("I'm Mr. Meeseeks, look at me!!") // other stuff then happens, but if Jerry asks to // remove 2 strokes from his golf game... panic("It's gettin' weird!") } 复制代码
虽然这个函数会panic,但你仍是不得不使用它,当它panic的时候咱们能够捕获这个错误,就像这样:
func doStuff() error { var err error // If there is a panic we need to recover in a deferred func defer func() { if r := recover(); r != nil { err = errors.New("the meeseeks went crazy!") } }() pressButton() return err } 复制代码
当pressButton发生panic的时候,咱们会觉得将会返回一个error,但结果是返回一个nil。是由于pressButton发生panic了就直接返回了,并不会走到return err。
想修复这个问题很简单,只需给error起一个变量名就行了。
func doStuff() (err error) { // If there is a panic we need to recover in a deferred func defer func() { if r := recover(); r != nil { err = errors.New("the meeseeks went crazy!") } }() pressButton() return err } 复制代码
1.《理解 Go make 和 new 的区别》 sanyuesha.com/2017/07/26/…
2.《Using named return variables to capture panics in Go》 www.calhoun.io/using-named…
3.dave.cheney.net/2019/01/29/…
感谢阅读,欢迎你们指正,留言分享交流~