Learning Go: 能像学脚本语言一样学习Go吗?

Go语言的开发效率很高,语法表达能力很强,以至于很多时候我们几乎可以把它当成Python一样的脚本语言来用。但是Go毕竟是一种 system programming language,如果不能像学习C/C++一样,深入语言实现,有时候会有很挠头的情况出现。

比如这个使用map来统计每个广告的点击率(展示次数和点击次数)的例子,编译竟然不能通过!

package main
import "fmt"

type CTR struct {
        click int
        impression int
}

func main() {
        ads_ctr := make(map[string]CTR)
        ads_ctr["P&G"] = CTR{3, 30}
        ads_ctr["P&G"].click += 3  // compiler complains!
        fmt.Println(ads_ctr["P&G"])
}

Go编译器报错的那一行,ads_ctr["P&G"].click += 3,要是让Javascript或者Python解释器去看,不会有什么问题。就算让C++编译器去看,也不会有问题。但是Go的编译器很坚持原则 —— map 里存的values可以修改,但是只能整体改变。比如这样:

func main() {
        ads_ctr := make(map[string]CTR)
        ads_ctr["P&G"] = CTR{3, 30}
        a := ads_ctr["P&G"]
        a.click += 3
        ads_ctr["P&G"] = a
        fmt.Println(ads_ctr["P&G"])
}

如果map的value不是CTR这样的小东西,而是一个比较大的数据结构,上面这样的update的开销就太大了点。这时候,我们会希望map的value是个指针。比如:

func main() {
        ads_ctr := make(map[string]*CTR)
        ads_ctr["P&G"] = new(CTR)
        ads_ctr["P&G"].click += 3;
        ads_ctr["P&G"].impression += 30;
        fmt.Println(*ads_ctr["P&G"])
}

看看,这样的用法是不是让你想起STL container中的value最好是指针的建议?为什么Go编译器如此强硬的要求(而不只是建议)呢?至少有一个原因是避免复杂结构的 copy construction(拷贝构造)。