初探go-golang语言初体验
2017/10/20
一、初体验 1、环境 wgethttps://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz tar-C/usr/local-xzfgo1.8.linux-amd64.tar.gz cat<<'_EOF'>>/etc/profile #golang exportPATH=$PATH:/usr/local/go/bin exportGOPATH=/opt/go _EOF source/etc/profile 2、教程 #gotooltour& 访问:http://127.0.0.1:3999/ 3、第一个程序 #cd$GOPATH #mkdirsrc/abc.com/demo/hello-p #vimsrc/abc.com/demo/hello/hello.go packagemain import"fmt" funcmain(){ fmt.Printf("Hello,world.\n") } #goinstallabc.com/demo/hello #bin/hello Hello,world. 4、第一个包 #mkdirsrc/abc.com/demo/stringutil-p #vimsrc/abc.com/demo/stringutil/reverse.go //Packagestringutilcontainsutilityfunctionsforworkingwithstrings. packagestringutil //Reversereturnsitsargumentstringreversedrune-wiselefttoright. funcReverse(sstring)string{ r:=[]rune(s) fori,j:=0,len(r)-1;i<len(r)/2;i,j=i+1,j-1{ r[i],r[j]=r[j],r[i] } returnstring(r) } #gobuildabc.com/demo/stringutil #catsrc/abc.com/demo/hello/hello.go packagemain import( "fmt" "abc.com/demo/stringutil" ) funcmain(){ fmt.Printf(stringutil.Reverse("!oG,olleH")) } #goinstallabc.com/demo/hello #bin/hello Hello,Go! 5、目录结构 #tree/opt/go /opt/go ├──bin#install后生成的可执行文件目录 │└──hello ├──pkg#install后生成的包目录 │└──linux_amd64 │└──abc.com │└──demo │└──stringutil.a └──src#源码目录 └──abc.com └──demo ├──hello │└──hello.go └──stringutil └──reverse.go 10directories,4files 6、引入测试 #vimsrc/abc.com/demo/stringutil/reverse_test.go packagestringutil import"testing" funcTestReverse(t*testing.T){ cases:=[]struct{ in,wantstring }{ {"Hello,world","dlrow,olleH"},{"Hello,世界","界世,{"",""},} for_,c:=rangecases{ got:=Reverse(c.in) ifgot!=c.want{ t.Errorf("Reverse(%q)==%q,want%q",c.in,got,c.want) } } } #gotestabc.com/demo/stringutil okabc.com/demo/stringutil0.007s 7、使用远程的包 示例,从git上指定的url获取包,goget将完成fetch,build和install的操作: #gogetgithub.com/golang/example/hello #bin/hello Hello,Goexamples! 8、查看当前go的环境变量 [root@tvm01go]#goenv GOARCH="amd64" GOBIN="" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/opt/go" GORACE="" GOROOT="/usr/local/go" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" GOGCCFLAGS="-fPIC-m64-pthread-fmessage-length=0-fdebug-prefix-map=/tmp/go-build679741147=/tmp/go-build" CXX="g++" CGO_ENABLED="1" PKG_CONFIG="pkg-config" CGO_CFLAGS="-g-O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g-O2" CGO_FFLAGS="-g-O2" 9、重新编译go源码 1)源码 需求:使用goget的时候,看不到下载的进度条。 目标:调整go源码,重新编译 [root@tvm01src]#pwd /usr/local/go/src [root@tvm01src]#vimcmd/go/vcs.go varvcsGit=&vcsCmd{ (略) createCmd:[]string{"clone{repo}{dir}","-go-internal-cd{dir}submoduleupdate--init--recursive"},downloadCmd:[]string{"pull--ff-only","submoduleupdate--init--recursive"},变更为: createCmd:[]string{"clone--progress{repo}{dir}",(略) func(v*vcsCmd)run1(dirstring,cmdlinestring,keyval[]string,verbosebool)([]byte,error){ (略) cmd.Stdout=&buf cmd.Stderr=&buf 变更为: cmd.Stdout=&buf cmd.Stderr=&buf cmd.Stdout=os.Stdout cmd.Stderr=os.Stderr (略) 2)编译 [root@tvm01src]#./all.bash #####BuildingGobootstraptool. cmd/dist ERROR:$GOROOT_BOOTSTRAPmustnotbesetto$GOROOT Set$GOROOT_BOOTSTRAPtoaworkingGotree>=Go1.4. 解决办法:编译go1.4,然后再重试 unsetGOPATH unsetGOROOT cd/opt mkdirgo1.4_src gitclonehttps://github.com/golang/go.git cdgo gitcheckout-b1.4.3go1.4.3 cdsrc ./all.bash cd../.. cp-ago/root/go1.4 cd/usr/local/go [root@tvm01src]#./all.bash 重新测试: [root@tvm01src]#source/etc/profile [root@tvm01src]#goget-vgithub.com/docker/docker/client github.com/docker/docker(download) Cloninginto'/opt/go/src/github.com/docker/docker'... remote:Countingobjects:234999,done. remote:Compressingobjects:100%(24/24),done. Receivingobjects:6%(15150/234999),4.64MiB|345.00KiB/s 符合预期。 二、试着写一个小的程序 1、设定目标 1)尽量多的用到go语言的语法基础内容:packages,variables,functionsFlowcontrol,method,interface,concurrency 2)请求url,获取状态等; 2、代码示例 [root@tvm01go]#catsrc/abc.com/demo/demoHttpHead/app.go /* #demoHttpHead #2017/10/20 */ packagemain import( "flag" "fmt" "log" "sync" "time" "net/http" "io/IoUtil" "strings" "strconv" ) typetaskStatestruct{ vmap[string]int muxsync.Mutex } func(ts*taskState)Inc(keystring){ ts.mux.Lock() ts.v[key]++ ts.mux.Unlock() } func(ts*taskState)Value(keystring)int{ ts.mux.Lock() deferts.mux.Unlock() returnts.v[key] } funchandleError(errerror,methodstring)bool{ iferr!=nil{ log.Printf("[E]%s:%v",err) returntrue } returnfalse } funcgetHosts()([]string){ varhosts[]string data,err:=IoUtil.ReadFile("urls.txt") ifhandleError(err,"IoUtil.ReadFile"){ returnhosts } for_,h:=rangestrings.Split(string(data),"\n"){ ifh==""{ continue } hosts=append(hosts,h) } returnhosts } funchandleHttpHeadReq(seqint,urlstring,chchanstring,stat*taskState){ head,err:=http.Head(url) ifhandleError(err,"http.Head"){ stat.Inc("failure") ch<-"["+strconv.Itoa(seq)+"]"+url+":Failed." return } stat.Inc("success") status:=head.Status ch<-"["+strconv.Itoa(seq)+"]"+url+":"+status } funcmain(){ dtStart:=time.Now() cnt:=flag.Int("c",10,"[]setNtimestorequestthehttpurl.") fromCfg:=flag.Bool("f",false,"[]parseurlsfromfile:[urls.txt]ornot?") flag.Parse() varstat=taskState{v:make(map[string]int)} varhosts[]string if*fromCfg==true{ hosts=getHosts() }else{ hosts=flag.Args() } for_,url:=rangehosts{ ch:=make(chanstring) fori:=0;i<*cnt;i++{ gohandleHttpHeadReq(i,url,ch,&stat) } fort:=0;t<*cnt;t++{ fmt.Println(<-ch) } } log.Printf("success:%d,failure:%d,TimeCost:%v\n",stat.Value("success"),stat.Value("failure"),time.Since(dtStart)) } 3、如何运行 1)直接运行 [root@tvm01go]#gorunsrc/abc.com/demo/http_status/http_status.go-h Usageof/tmp/go-build822199343/command-line-arguments/_obj/exe/http_status: -cint []setNtimestorequestthehttpurl.(default10) -f[]parseurlsfromfile:[urls.txt]ornot? exitstatus2 [root@tvm01go]#gorunsrc/abc.com/demo/demoHttpHead/app.go-c3http://www.baidu.com [2]http://www.baidu.com:200OK [0]http://www.baidu.com:200OK [1]http://www.baidu.com:200OK 2017/10/2011:12:15success:3,failure:0,TimeCost:20.514834ms [root@tvm01go]#gorunsrc/abc.com/demo/demoHttpHead/app.go-c3http://www.baidu.comhttp://www.taobao.com [2]http://www.baidu.com:200OK [0]http://www.baidu.com:200OK [1]http://www.baidu.com:200OK [2]http://www.taobao.com:200OK [1]http://www.taobao.com:200OK [0]http://www.taobao.com:200OK 2017/10/2011:12:33success:6,TimeCost:131.9136ms 2)编译 当前为linux环境 [root@tvm01go]#goinstallabc.com/demo/demoHttpHead 运行 [root@tvm01go]#./bin/demoHttpHead-h Usageof./bin/demoHttpHead: -cint []setNtimestorequestthehttpurl.(default10) -f []parseurlsfromfile:[urls.txt]ornot? [root@tvm01go]#./bin/demoHttpHead-c5http://www.taobao.com [3]http://www.taobao.com:200OK [2]http://www.taobao.com:200OK [1]http://www.taobao.com:200OK [0]http://www.taobao.com:200OK [4]http://www.taobao.com:200OK 2017/10/2011:13:37success:5,TimeCost:107.063734ms 3)交叉编译 以windows平台为例: [root@tvm01go]#GOOS="windows"goinstallabc.com/demo/demoHttpHead [root@tvm01go]#szbin/windows_amd64/abc.com/demo/demoHttpHead.exe 下载到windows下执行,符合预期 三、FAQ 1、访问golang.org异常 注1:引用【docker深入2-UI之portainer的二次开发】文章的实例 构建app [root@dev_08portainer]#gruntbuild 如果遇到这样的错误: Buildingportainerforlinux-amd64 /go/src/github.com/portainer/portainer/crypto/crypto.go:4:2:cannotfindpackage"golang.org/x/crypto/bcrypt"inanyof: /usr/local/go/src/golang.org/x/crypto/bcrypt(from$GOROOT) /go/src/golang.org/x/crypto/bcrypt(from$GOPATH) /go/src/github.com/portainer/portainer/http/handler/websocket.go:21:2:cannotfindpackage"golang.org/x/net/websocket"inanyof: /usr/local/go/src/golang.org/x/net/websocket(from$GOROOT) /go/src/golang.org/x/net/websocket(from$GOPATH) mv:cannotstat‘api/cmd/portainer/portainer-linux-amd64’:Nosuchfileordirectory Warning:CommandFailed:build/build_in_container.shlinuxamd64 mv:cannotstat‘api/cmd/portainer/portainer-linux-amd64’:Nosuchfileordirectory Use--forcetocontinue. Abortedduetowarnings. 那是因为网络可达性问题,国内访问golang.org异常。 [root@dev_08portainer]#hostgolang.org golang.orgisanaliasforgolang-consa.l.google.com. golang-consa.l.google.comhasaddress216.239.37.1 导致这2个依赖下载失败: golang.org/x/crypto/bcrypt golang.org/x/net/websocket 解决方法: [root@dev_08portainer]#gogetgithub.com/golang/crypto/tree/master/bcrypt [root@dev_08portainer]#gogetgithub.com/golang/net/tree/master/websocket [root@dev_08portainer]#cd$GOPATH/src [root@dev_08src]#mkdirgolang.org/x-p [root@dev_08src]#mvgithub.com/golang/*golang.org/x/ 然后再切换到源码目录,调整构建脚本: [root@dev_08src]#cd/opt/portainer [root@dev_08portainer]#vimbuild/build_in_container.sh 挂载本地的$GOPATH/src/golang.org到容器路径:/go/src/golang.org dockerrun--rm-tv$(pwd)/api:/src-eBUILD_GOOS="$1"-eBUILD_GOARCH="$2"portainer/golang-builder:cross-platform/src/cmd/portainer 调整为: dockerrun--rm-tv$(pwd)/api:/src-v$GOPATH/src/golang.org:/go/src/golang.org-eBUILD_GOOS="$1"-eBUILD_GOARCH="$2"portainer/golang-builder:cross-platform/src/cmd/portainer 最后重新构建一次: [root@dev_08portainer]#gruntbuild (略) Cleaning"dist/js/angular.37dfac18.js"...OK Cleaning"dist/js/portainer.cab56db9.js"...OK Cleaning"dist/js/vendor.4edc9b0f.js"...OK Cleaning"dist/css/portainer.e7f7fdaa.css"...OK Done,withouterrors. 看到上述输出,表示符合预期。 XYXW、参考 1、golang https://golang.org/doc https://golang.org/doc/code.html#Workspaces 2、the-way-to-go_ZH_CN https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md 3、解决升级go版本遇到的Set$GOROOT_BOOTSTRAPtoaworkingGotree>=Go1.4.问题 http://blog.csdn.net/qq_15437667/article/details/59776840 4、国内下载golang.org的包有什么好办法么? https://gocn.io/question/362