入门

入门

golang 特性简介

文章分享sheepbao 发表了文章 • 0 个评论 • 1016 次浏览 • 2017-01-22 16:37 • 来自相关话题

golang 特性简介

by sheepbao

主要大概介绍go语言的历史和特性,简单的入门。

来历

很久以前,有一个IT公司,这公司有个传统,允许员工拥有20... 查看全部

golang 特性简介


by sheepbao


主要大概介绍go语言的历史和特性,简单的入门。


来历


很久以前,有一个IT公司,这公司有个传统,允许员工拥有20%自由时间来开发实验性项目。在2007的某一天,公司的几个大牛,正在用c++开发一些比较繁琐但是核心的工作,主要包括庞大的分布式集群,大牛觉得很闹心,后来c++委员会来他们公司演讲,说c++将要添加大概35种新特性。这几个大牛的其中一个人,名为:Rob Pike,听后心中一万个xxx飘过,“c++特性还不够多吗?简化c++应该更有成就感吧”。于是乎,Rob Pike和其他几个大牛讨论了一下,怎么解决这个问题,过了一会,Rob Pike说要不我们自己搞个语言吧,名字叫“go”,非常简短,容易拼写。其他几位大牛就说好啊,然后他们找了块白板,在上面写下希望能有哪些功能(详见文尾)。接下来的时间里,大牛们开心的讨论设计这门语言的特性,经过漫长的岁月,他们决定,以c语言为原型,以及借鉴其他语言的一些特性,来解放程序员,解放自己,然后在2009年,go语言诞生。


思想


Less can be more


大道至简,小而蕴真


让事情变得复杂很容易,让事情变得简单才难


深刻的工程文化


优点



  1. 自带gc。

  2. 静态编译,编译好后,扔服务器直接运行。

  3. 简单的思想,没有继承,多态,类等。

  4. 丰富的库和详细的开发文档。

  5. 语法层支持并发,和拥有同步并发的channel类型,使并发开发变得非常方便。

  6. 简洁的语法,提高开发效率,同时提高代码的阅读性和可维护性。

  7. 超级简单的交叉编译,仅需更改环境变量。(花了我两天时间编译一个imagemagick到arm平台)

  8. 内含完善、全面的软件工程工具。Go语言自带的命令和工具相当地强大。通过它们,我们可以很轻松地完成Go语言程序的获取、编译、测试、安装、运行、运行分析等一系列工作,这几乎涉及了开发和维护一个软件的所有环节。


hello


package main

func main(){
println("hello, sewise")
}

type


主要讲讲特有的类型,其他基本类型不做介绍


slice


切片:可以理解为动态数组,类似c++的vector
声明一个slice


    var slice []T
如:
var ints []int

slice的追加


    ints=append(ints,1)
ints=append(ints,2,3,4,5)

slice的截取


    newInts1:=ints[2:3]
newInts2:=ints[2:]
newInts3:=ints[:4]

map


字典:键值对


    var json map[string]string

interface


接口:方法的集合,是一种合约
栗子:
声明一个bird接口


    var bird interface{
fly()
}

声明一个hen对象(实现bird接口)


    type hen struct {
weight int
hasFeather bool
}

func (h hen)fly(){
fmt.Println("iI can fly")
}

type func (h hen)eat(){
h.weight++
fmt.Println("yes, I can eat")
}

声明一个pig对象(未实现bird接口,因为pig不会fly)


    type pig struct {
age int
weignt int
hasFeather bool
}

func (p pig)run(){
fmt.Println("I can run")
}

func (p pig)eat(){
p.weight += 100
fmt.Println("Yes, I can eat so much")
}

func (p pig)sleep(){
fmt.Println("I slept all my life")
}

// pig can't fly

channel


通道:轻量集队列,传递某种类型的值的通道


    var ch chan int
ch=make(chan int,1)

往ch写入一个数据


    ch<-8888

从ch读取数据


    out:=<-ch

特性:
channel是有长度的,当channel的缓冲为满时,再往里写入就会阻塞,当channel的缓冲为空时,从channel读就会阻塞


package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int)
fmt.Println("ch len:", len(ch))
go func() {
// 往缓冲满的channel里写数据(阻塞)
// ch <- 1
// 从缓冲为空的channel里读数据(阻塞)
<-ch
fmt.Println("I am in minor goroutine")
}()
fmt.Println("I am in main goroutine")
time.Sleep(2 * time.Second)
}

当长度为0是,就是不带缓冲的channel
长度大于0,就是带缓冲的channel


并发


关键字:go 启动go程
一个普通的函数或方法调用前加上关键字go,即可启动一个goroutine


    go func(){
fmt.Println("start func")
time.Sleep(120*time.Second)
}()

竞争条件检测
-race
race.go


package main

import (
"fmt"
"time"
)

func main() {
a := 1
go func() {
a = 2
}()
a = 3
fmt.Println("a is ", a)

time.Sleep(2 * time.Second)
}

检测:执行go run -race race.go


a is  3
==================
WARNING: DATA RACE
Write at 0x00c420072188 by goroutine 6:
main.main.func1()
/Users/bao/program/go/gowork/hello/src/research/race.go:11 +0x3b

Previous write at 0x00c420072188 by main goroutine:
main.main()
/Users/bao/program/go/gowork/hello/src/research/race.go:13 +0x9f

Goroutine 6 (running) created at:
main.main()
/Users/bao/program/go/gowork/hello/src/research/race.go:12 +0x8e
==================
Found 1 data race(s)

结果分析:
goroutine6运行到第11行和main goroutine运行到13行的时候触发竞争了。而且goroutine6是在第12行的时候产生的。


package


包的管理,关键字importGOPATH


gopath


gopath是一个路径列表,存放go项目工程
GOPATH文件目录结构


├── bin  二进制文件目录
├── pkg 编译好的库文件目录
└── src 源码目录

平常项目的目录结构


├── bin  二进制文件目录
├── pkg 编译好的库文件目录
└── src 源码目录
├── main 入口函数目录
└── vendor 当前项目的库目录
└── sheepbao.com
└── glog

import


比如上面的项目,我要在main.go引入glog


package main

// 引入glog包
import "sheepbao.com/glog"

func main(){
glog.Println("test")
}

go的工程工具简介


test


go的命令工具 test,用来做测试


单元测试


go test
只测试函数名被它正确匹配的测试函数
go test -v -run="French|Canal"


栗子:
add.go


package test

func addOne(i int) int {
return i + 1
}

add_test.go


package test

import "testing"

func TestAddOne(t *testing.T) {
result := addOne(1)
if result != 2 {
t.Error("1+1!=2")
}
}

bao@baoMac test$ go test -v .
=== RUN TestAddOne
--- PASS: TestAddOne (0.00s)
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/test 0.006s

基准测试


go test -bench=.
内存的分配情况
go test -bench=FuncName -benchmem
栗子:
stringsCon.go


package bench

import (
"fmt"
)

func Sprintf(s1, s2, s3 string) string {
return fmt.Sprintf("%s%s%s", s1, s2, s3)
}

func AddString(s1, s2, s3 string) string {
return s1 + s2 + s3
}

stringCon_test.go


package bench

import "testing"

var (
s1 = "make it run!"
s2 = "make it right!"
s3 = "make it fast!"
)

func BenchmarkSprintf(b *testing.B) {
for i := 0; i < b.N; i++ {
Sprintf(s1, s2, s3)
}
}

func BenchmarkAddString(b *testing.B) {
for i := 0; i < b.N; i++ {
AddString(s1, s2, s3)
}
}

go test -bench=.


bao@baoMac bench$ go test -bench=.
testing: warning: no tests to run
BenchmarkSprintf-4 5000000 349 ns/op
BenchmarkAddString-4 20000000 61.7 ns/op
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/bench 3.414s

样本测试


package et

import (
"fmt"
)

func ExampleHello() {
fmt.Println("hello, sewise")
// Output: hello, sewise
}

bao@baoMac example$ go  test -v .
=== RUN ExampleHello
--- PASS: ExampleHello (0.00s)
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/example 0.006s

如果把上面的// Output: hello, sewise改为// Output: hello, sewis
则样本测试不能通过


bao@baoMac example$ go  test -v .
=== RUN ExampleHello
--- FAIL: ExampleHello (0.00s)
got:
hello, sewise
want:
hello, sewis
FAIL
exit status 1
FAIL _/Users/bao/program/go/gowork/hello/src/research/example 0.006s

pprof


go的命令工具 pprof,用来性能分析(内存使用,泄露和cpu消耗)
go tool pprof



可视化(原是svg文件,下图为截图):


image_1b72f233avto14d7on4h3nlm51g.png-129.8kB



可视化(原是svg文件,下图为截图:


image_1b72euk7b1knr1d1n1ugq2pe19kim.png-176.7kB


go tool pprof --text http://localhost:6060/debug/pprof/heap


go命令教程


资料


http://www.csdn.net/article/2012-07-04/2807113-less-is-exponentially-more


http://www.jianshu.com/p/91e40c3e3acb?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


http://smallsoho.com/2016/11/20/Go简明教程.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


大牛真身


最大牌的当属B和C语言设计者、Unix和Plan 9创始人、1983年图灵奖获得者Ken Thompson,这份名单中还包括了Unix核心成员Rob Pike(go语言之父)、java HotSpot虚拟机和js v8引擎的开发者Robert Griesemer、Memcached作者Brad Fitzpatrick,等等。


功能



  • 规范的语法(不需要符号表来解析)

  • 垃圾回收(独有)

  • 无头文件

  • 明确的依赖

  • 无循环依赖

  • 常量只能是数字

  • int和int32是两种类型

  • 字母大小写设置可见性(letter case sets visibility)

  • 任何类型(type)都有方法(不是类型)

  • 没有子类型继承(不是子类)

  • 包级别初始化以及明确的初始化顺序

  • 文件被编译到一个包里

  • 包package-level globals presented in any order

  • 没有数值类型转换(常量起辅助作用)

  • 接口隐式实现(没有“implement”声明)

  • 嵌入(不会提升到超类)

  • 方法按照函数声明(没有特别的位置要求)

  • 方法即函数

  • 接口只有方法(没有数据)

  • 方法通过名字匹配(而非类型)

  • 没有构造函数和析构函数

  • postincrement(如++i)是状态,不是表达式

  • 没有preincrement(i++)和predecrement

  • 赋值不是表达式

  • 明确赋值和函数调用中的计算顺序(没有“sequence point”)

  • 没有指针运算

  • 内存一直以零值初始化

  • 局部变量取值合法

  • 方法中没有“this”

  • 分段的堆栈

  • 没有静态和其它类型的注释

  • 没有模板

  • 内建string、slice和map

  • 数组边界检查

Python 程序员的 Golang 学习指南(IV): 包管理篇

文章分享Cloudinsight 发表了文章 • 2 个评论 • 635 次浏览 • 2016-10-19 19:08 • 来自相关话题

Authors: startover

Authors: startover





第一篇文章我们有提到,Golang 官方并没有推荐最佳的包管理方案,对于像我这样习惯了 Python 包管理的开发者,自然还是希望有像 pip 一样好用的工具,帮助我们进行依赖管理,下面就让我们对 Golang 的包管理机制一探究竟。


Golang 包管理机制


Go 语言的包管理系统是去中心化的,我们可以通过 go get 命令获取存放在远程仓库的代码协议。实际上,go get 支持以下 VCS 协议:
































名称 主命令 说明
Mercurial hg Mercurial是一种轻量级分布式版本控制系统,采用Python语言实现,易于学习和使用,扩展性强。
Git git Git最开始是Linux Torvalds为了帮助管理 Linux 内核开发而开发的一个开源的分布式版本控制软件。但现在已被广泛使用。它是被用来进行有效、高速的各种规模项目的版本管理。
Subversion svn Subversion是一个版本控制系统,也是第一个将分支概念和功能纳入到版本控制模型的系统。但相对于Git和Mercurial而言,它只算是传统版本控制系统的一员。
Bazaar bzr Bazaar是一个开源的分布式版本控制系统。但相比而言,用它来作为VCS的项目并不多。

比如,我们现在需要获取 godep 这个项目,可以执行如下命令:


$ go get github.com/tools/godep

需要指出的是,go get 实际上执行了两个步骤:1. 下载源码包;2. 执行 go install,如果只下载不安装,则需要指定 -d 参数,如下:


$ go get -d github.com/tools/godep

除了 go get,Go 语言还提供了一个 Workspace 的机制,即通过设定 GOPATH 环境变量,指定除了 GOROOT 所指定的目录之外,Go 代码所在的位置(也就是 Workspace 的位置)。 一般来说,GOPATH 目录下会包含 pkg、src 和 bin 三个子目录,这三个目录各有用处。



  • bin 目录用于放置编译好的可执行文件,为了使得这里的可执行文件可以方便的运行, 可在 shell 中设置 PATH 环境变量。

  • src 目录用于放置代码源文件,在进行 import 时,是使用这个位置作为根目录的。自己编写的代码也应该放在这下面。

  • pkg 用来放置安装的包的链接对象(Object)的。这个概念有点类似于链接库,Go 会将编译出的可连接库放在这里, 方便编译时链接。不同的系统和处理器架构的对象会在 pkg 存放在不同的文件夹中。


Golang 包管理现状


显然,通过 go getWorkspace 的方式并不足以解决项目依赖和版本依赖的问题,主要有以下几点:



  1. 第三方包的版本控制。如果没有明确指定依赖的第三方包的版本,团队开发很容易导入不一样的版本,导致项目无法正常运行。

  2. 第三方包没有内容安全审计,很容易引入代码 Bug,这是泛中心化包管理普遍存在的问题。

  3. 依赖的完整性无法校验,程序编译时无法保障百分百成功。


因此,我们必须借助第三方工具来解决这些问题。


第三方解决方案


这里我从官方推荐包管理工具中挑选了几个比较常用的工具:Godep, Govendor 以及 Glide,作下简单介绍。


Godep



  • godep save


这个命令做了以下几件事:




  1. 查找项目中所用到的所有的第三方包。

  2. 在项目目录下创建 Godeps 目录,Godeps/Godeps.json 是依赖文件,包括了 go 的版本,用到的第三方包的引入路径,版本号等信息,json 文件需要一并加入到版本控制里。

  3. 所有依赖的第三方包的代码会被拷贝到 vendor/ 下,并且移除了 .git 这样的版本控制信息。




  • godep restore


当下载别人发布的项目时,如果下载的项目中只有 Godeps.json 文件,而没有包含第三方包,则可以使用 godep restore 这个命令将所有的依赖包下载到 $GOPATH 目录下,而不用一个一个去 go get,还是很方便的。


Govendor



  • govendor init


执行 govendor init 会在根目录下生成一个 vendor 文件夹,以及 vendor/vendor.json,其中 vendor.json 类似 godep 工具中的描述文件版本的功能。



  • govendor add +external


执行 govendor add +external 会将所有依赖的第三方包的代码拷贝到 vendor 文件夹下,并且移除了 .git 这样的版本控制信息,测试所需依赖以及依赖项目的测试文件。与 godep save 的功能类似。



  • govendor fetch


执行 govendor fetch 新增的第三方包直接被 get 到根目录的 vendor 文件夹下,不会与其它的项目混用第三方包,完美避免了多个项目同用同一个第三方包的不同版本问题。


这样,我们只需对 vendor/vendor.json 进行版本控制,即可对第三包依赖关系进行控制。


Glide



  • glide init


执行 glide initglide create 会在项目根目录下生成一个 glide.yaml,这个文件用来记录项目用到的第三方包的依赖关系,并支持编辑修改。



  • glide install


执行 glide install,会把所有依赖的第三方包都下载到 vendor 文件夹下,并且会在 glide.yaml 中添加所有依赖的第三方包名称,以及在 glide.lock 文件中记录具体的版本管理信息。


总结


上面我们分别对 Godep, Govendor 以及 Glide 这三种工具做了简单的介绍,对于 Python 开发者,个人还是比较认同 Govendor 的方式,因为其很容易实现类似 Virtualenv 的模式,从而实现不同程序使用不同版本依赖的目的。


当然,如果你是 Node.js 的开发者,可能对于 Godep 有更加熟悉的感觉,而对于 Ruby 开发者,gom 会让你感到更加亲切。


因此,针对第三方包管理工具的选择,现阶段还完全交由开发者做裁定,这里就“仁者见仁,智者见智”了。


相关链接:

http://www.infoq.com/cn/articles/golang-package-management

https://io-meter.com/2014/07/30/go's-package-management/

https://github.com/golang/go/wiki/PackageManagementTools




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(III): 入门篇

文章分享Cloudinsight 发表了文章 • 0 个评论 • 1575 次浏览 • 2016-10-14 15:39 • 来自相关话题

Authors: startover

Authors: startover





基础语法


类型和关键字



  • 类型


// 基础类型
布尔类型: bool
整型: int8,uint8,int16,uint16,int32,uint32,int64,uint64,int,rune,byte,complex128, complex64,其中,byte 是 int8 的别名
浮点类型: float32 、 float64
复数类型: complex64 、 complex128
字符串: string
字符类型: rune(int32的别名)
错误类型: error

// 复合类型
指针(pointer)
数组(array)
切片(slice)
字典(map)
通道(chan)
结构体(struct)
接口(interface)


  • 关键字


break        default      func         interface    select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

变量


Go 同其他语言不同的地方在于变量的类型在变量名的后面,不是 int a,而是 a int。至于为什么这么定义,Go 的官方博客有给出解释,有兴趣的可以参考下。


变量定义语法如下:


var a int
a = 2

// 或者
a := 2

// 同时定义多个变量
var (
a int
b bool
)

// 同时给多个变量赋值
a, b := 2, true

操作符


+    &     +=    &=     &&    ==    !=    (    )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^=

控制结构


Go 语言支持如下的几种流程控制语句:



  • 条件语句,对应的关键字为 if、else 和 else if;

  • 选择语句,对应的关键字为 switch、case 和 select;

  • 循环语句,对应的关键字为 for 和 range;

  • 跳转语句,对应的关键字为 goto。


值得一提的是,Go 语言并不支持 do 或者 while 关键字,而是对 for 关键字做了增强,以实现类似的效果,如下:


for {
// 实现无限循环,慎用!
}

常用内置函数



  • len:计算(字符串,数组或者切片,map)长度

  • cap:计算(数组或者切片,map)容量

  • close:关闭通道

  • append:追加内容到切片

  • copy:拷贝数组/切片内容到另一个数组/切片

  • delete:用于删除 map 的元素


array, slice 和 map


// array
a := [3]int{ 1, 2, 3 } // 等价于 a := [...]int{ 1, 2, 3 }

// slice
s := make([]int , 3) // 创建一个长度为 3 的 slice
s := append(s, 1) // 向 slice 追加元素
s := append(s, 2)

// map
m := make(map[string]int) // 使用前必须先初始化
m["golang"] = 7

关于 array, slice 和 map 的更多惯用法,有一篇文章介绍的挺详细,有兴趣的可以看看。


函数


Go 语言的函数有如下特性:



  • 不定参数


由于 Go 语言不支持函数重载(具体原因见 Go Language FAQ),但我们可以通过不定参数实现类似的效果。


func myfunc(args ...int) {
// TODO
}

// 可通过如下方式调用
myfunc(2)
myfunc(1, 3, 5)


  • 多返回值


与 C、C++ 和 Java 等开发语言的一个极大不同在于,Go 语言的函数或者成员的方法可以有多
个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码。


func (file *File) Read(b []byte) (n int, err error)

// 我们可以通过下划线(_)来忽略某个返回值
n, _ := f.Read(buf)


  • 匿名函数


匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯
到 1958 年的 Lisp 语言。但是由于各种原因,C 和 C++ 一直都没有对匿名函数给以支持,其他的各
种语言,比如 JavaScript、C# 和 Objective-C 等语言都提供了匿名函数特性,当然也包含Go语言。


匿名函数由一个不带函数名的函数声明和函数体组成,如下:


func(a, b int) bool {
return a < b
}

匿名函数可以直接赋值给一个变量或者直接执行:


f := func(a, b int) bool {
return a < b
}

func(a, b int) bool {
return a < b
}(3, 4) // 花括号后直接跟参数列表表示函数调用


  • 闭包


闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者
任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含
在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环
境(作用域)。


Go 的匿名函数就是一个闭包。我们来看一个例子:


package main

import "fmt"

func main() {
j := 5
a := func() func() {
i := 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}()
a()
j *= 2
a()
}

程序输出如下:


i, j: 10, 5
i, j: 10, 10

错误处理


Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try...catch...finally 这种异常,因为 Go 语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在 Go 语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了),才使用 Go 中引入的Exception处理:defer, panic, recover。


用法如下:


package main

import "fmt"

func main() {
defer func() {
fmt.Println("recovered:", recover())
}()
panic("not good")
}

关于 Go 语言的错误处理机制和传统的 try...catch...finally 异常机制孰优孰劣,属于仁者见仁,智者见智,这里不做赘速。有兴趣的同学可以去看看知乎上的讨论:Go 语言的错误处理机制是一个优秀的设计吗?


面向对象 -> 一切皆类型


Python 推崇“一切皆对象”,而在 Go 语言中,类型才是一等公民。


我们可以这样定义一个结构体:


type Name struct {
First string
Middle string
Last string
}

同样也可以定义基础类型:


type SimpleName string

还能给任意类型定义方法:


func (s SimpleName) String() string { return string(s) }
// 或者
func (s string) NoWay()

Golang VS Python


最后我们通过几个例子来比较一下 Golang 与 Python 的一些基本用法,如下:


生成器(Generator)



  • Python 版本


def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
yield a

for x in fib(10):
print x

print 'done'


  • Golang 版本


package main

import "fmt"

func fib(n int) chan int {
c := make(chan int)
go func() {
a, b := 0, 1
for i := 0; i < n; i++ {
a, b = b, a+b
c <- a
}
close(c)
}()
return c
}

func main() {
for x := range fib(10) {
fmt.Println(x)
}
}

装饰器(Decorator)



  • Python 版本


from urlparse import urlparse, parse_qs
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

def auth_required(myfunc):
def checkuser(self):
user = parse_qs(urlparse(self.path).query).get('user')
if user:
self.user = user[0]
myfunc(self)
else:
self.wfile.write('unknown user')
return checkuser

class myHandler(BaseHTTPRequestHandler):
@auth_required
def do_GET(self):
self.wfile.write('Hello, %s!' % self.user)

if __name__ == '__main__':
try:
server = HTTPServer(('localhost', 8080), myHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()


  • Golang 版本


package main

import (
"fmt"
"net/http"
)

var hiHandler = authRequired(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))
},
)

func authRequired(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.FormValue("user") == "" {
http.Error(w, "unknown user", http.StatusForbidden)
return
}
f(w, r)
}
}

func main() {
http.HandleFunc("/hi", hiHandler)
http.ListenAndServe(":8080", nil)
}

猴子补丁(Monkey patching)



  • Python 版本


import urllib

def say_hi(usr):
if auth(usr):
print 'Hi, %s' % usr
else:
print 'unknown user %s' % usr

def auth(usr):
try:
auth_url = 'localhost'
r = urllib.urlopen(auth_url + '/' + usr)
return r.getcode() == 200
except:
return False

def sayhitest():
# Test authenticated user
globals()['auth'] = lambda x: True
say_hi('John')

# Test unauthenticated user
globals()['auth'] = lambda x: False
say_hi('John')

if __name__ == '__main__':
sayhitest()


  • Golang 版本


package main

import (
"fmt"
"net/http"
)

func sayHi(user string) {
if !auth(user) {
fmt.Printf("unknown user %v\n", user)
return
}
fmt.Printf("Hi, %v\n", user)
}

var auth = func(user string) bool {
authURL := "localhost"
res, err := http.Get(authURL + "/" + user)
return err == nil && res.StatusCode == http.StatusOK
}

func testSayHi() {
auth = func(string) bool { return true }
sayHi("John")

auth = func(string) bool { return false }
sayHi("John")
}

func main() {
testSayHi()
}

相关链接:

https://blog.golang.org/gos-declaration-syntax

https://se77en.cc/2014/06/30/array-slice-map-and-set-in-golang/

https://golang.org/doc/faq#overloading

https://www.zhihu.com/question/27158146

https://talks.golang.org/2013/go4python.slide




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注,及时获取最新文章~

Python 程序员的 Golang 学习指南(II): 开发环境搭建

文章分享Cloudinsight 发表了文章 • 0 个评论 • 1554 次浏览 • 2016-10-12 15:44 • 来自相关话题

Authors: startover

Authors: startover





上一篇文章我们已经对 Golang 有了初步的了解,这篇主要介绍如何在 Ubuntu 14.04 上搭建 Golang 开发环境。


安装 Golang


这里就按照官方文档进行安装即可,如下:



  • 下载并解压安装包到指定目录


$ wget https://storage.googleapis.com ... ar.gz
$ tar -C /usr/local -xzf go1.6.3.linux-amd64.tar.gz


  • 设置 PATH


$ echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
$ source ~/.bashrc


  • 验证安装


$ go version
go version go1.6.3 linux/amd64

环境变量设置


$ echo "export GOROOT=/usr/local/go" >> ~/.bashrc
$ echo "export GOPATH=$HOME/go" >> ~/.bashrc
$ source ~/.bashrc

其中,GOROOT 为 Golang 的安装目录,只有当 Golang 安装到除 /usr/local 之外的路径时需要设置,反之则不用设置,GOPATH 是 Golang 的开发目录,详细可参考官方文档


开发工具


工欲善其事,必先利其器,作为一名伪 VIMer,这里主要介绍下如何在 Vim 下配置 Golang 开发环境。


由于之前一直使用 k-vim 作为 Python 开发环境,而 k-vim 已经集成了当前使用最为广泛的用于搭建 Golang 开发环境的 vim 插件 vim-go,只是默认没有开启,需要我们手动进行相关设置。


k-vim 中开启 Golang 语言的支持,非常简单,如下:



  • 修改 ~/.vimrc.bundles(开启 golang 支持,并修改 vim-go 的默认配置,增加快捷键配置等)。


let g:bundle_groups=['python', 'javascript', 'markdown', 'html', 'css', 'tmux', 'beta', 'json', 'golang']

" vimgo {{{
let g:go_highlight_functions = 1
let g:go_highlight_methods = 1
let g:go_highlight_structs = 1
let g:go_highlight_operators = 1
let g:go_highlight_build_constraints = 1

let g:go_fmt_fail_silently = 1
let g:go_fmt_command = "goimports"
let g:syntastic_go_checkers = ['golint', 'govet', 'errcheck']

" vim-go custom mappings
au FileType go nmap <Leader>s <Plug>(go-implements)
au FileType go nmap <Leader>i <Plug>(go-info)
au FileType go nmap <Leader>gd <Plug>(go-doc)
au FileType go nmap <Leader>gv <Plug>(go-doc-vertical)
au FileType go nmap <leader>r <Plug>(go-run)
au FileType go nmap <leader>b <Plug>(go-build)
au FileType go nmap <leader>t <Plug>(go-test)
au FileType go nmap <leader>c <Plug>(go-coverage)
au FileType go nmap <Leader>ds <Plug>(go-def-split)
au FileType go nmap <Leader>dv <Plug>(go-def-vertical)
au FileType go nmap <Leader>dt <Plug>(go-def-tab)
au FileType go nmap <Leader>e <Plug>(go-rename)
au FileType go nnoremap <leader>gr :GoRun %<CR>
" }}}



  • 在 Vim 内执行 :PlugInstall,安装 vim-go




  • 在 Vim 内执行 :GoInstallBinaries,下载并安装 vim-go 依赖的二进制工具,goimportsgolint 等。



  • 安装 gotags,使 tagbar 配置生效。


$ go get -u github.com/jstemmer/gotags

我们来看一下最终效果:


Image of Golang Environment in Vim


编写第一个程序


进入工作目录,新建文件 hello.go,如下:


$ cd $GOPATH
$ vim hello.go
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

运行程序:


$ go run hello.go
Hello, World!



本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(I): Go 之初体验

文章分享Cloudinsight 发表了文章 • 3 个评论 • 1517 次浏览 • 2016-10-12 15:27 • 来自相关话题

Authors: startover

Authors: startover





Go 语言简介


Go,又称 golang,是 Google 开发的一种静态强类型,编译型,并发型,并具有垃圾回收功能的编程语言。


Go 语言于2009年11月正式宣布推出,自2012年发布1.0,最新稳定版1.7。目前,Go的相关工具和生态已逐渐趋于完善,也不乏重量级项目,如 Docker, Kubernetes, Etcd, InfluxDB 等。


Go 语言能解决什么样的问题


同绝大多数通用型编程语言相比,Go 语言更多的是为了解决我们在构建大型服务器软件过程中所遇到的软件工程方面的问题而设计的。乍看上去,这么讲可能会让人感觉 Go 非常无趣且工业化,但实际上,在设计过程中就着重于清晰和简洁,以及较高的可组合性,最后得到的反而会是一门使用起来效率高而且很有趣的编程语言,很多程序员都会发现,它有极强的表达力而且功能非常强大。


总结为以下几点:



  • 清晰的依赖关系

  • 清晰的语法

  • 清晰的语义

  • 偏向组合而不是继承

  • 提供简单的编程模型(垃圾回收、并发)

  • 强大的内置工具(gofmt、godoc、gofix等)


建议有兴趣的同学看看 Go在谷歌:以软件工程为目的的语言设计


Go 语言相对 Python 有哪些优势


这里引用一段知乎上某大牛的回答,如下:




  • 部署简单。Go 编译生成的是一个静态可执行文件,除了 glibc 外没有其他外部依赖。这让部署变得异常方便:目标机器上只需要一个基础的系统和必要的管理、监控工具,完全不需要操心应用所需的各种包、库的依赖关系,大大减轻了维护的负担。这和 Python 有着巨大的区别。由于历史的原因,Python 的部署工具生态相当混乱【比如 setuptools, distutils, pip, buildout 的不同适用场合以及兼容性问题】。官方 PyPI 源又经常出问题,需要搭建私有镜像,而维护这个镜像又要花费不少时间和精力。




  • 并发性好。Goroutine 和 channel 使得编写高并发的服务端软件变得相当容易,很多情况下完全不需要考虑锁机制以及由此带来的各种问题。单个 Go 应用也能有效的利用多个 CPU 核,并行执行的性能好。这和 Python 也是天壤之比。多线程和多进程的服务端程序编写起来并不简单,而且由于全局锁 GIL 的原因,多线程的 Python 程序并不能有效利用多核,只能用多进程的方式部署;如果用标准库里的 multiprocessing 包又会对监控和管理造成不少的挑战【我们用的 supervisor 管理进程,对 fork 支持不好】。部署 Python 应用的时候通常是每个 CPU 核部署一个应用,这会造成不少资源的浪费,比如假设某个 Python 应用启动后需要占用 100MB 内存,而服务器有 32 个 CPU 核,那么留一个核给系统、运行 31 个应用副本就要浪费 3GB 的内存资源。




  • 良好的语言设计。从学术的角度讲 Go 语言其实非常平庸,不支持许多高级的语言特性;但从工程的角度讲,Go 的设计是非常优秀的:规范足够简单灵活,有其他语言基础的程序员都能迅速上手。更重要的是 Go 自带完善的工具链,大大提高了团队协作的一致性。比如 gofmt 自动排版 Go 代码,很大程度上杜绝了不同人写的代码排版风格不一致的问题。把编辑器配置成在编辑存档的时候自动运行 gofmt,这样在编写代码的时候可以随意摆放位置,存档的时候自动变成正确排版的代码。此外还有 gofix, govet 等非常有用的工具。



  • 执行性能好。虽然不如 C 和 Java,但通常比原生 Python 应用还是高一个数量级的,适合编写一些瓶颈业务。内存占用也非常省。


从个人对 Golang 的初步使用来说,体验还是相当不错的,但是也有下面几点需要注意:




  • 驼峰式命名风格(依据首字母大小写来决定其是否能被其他包引用),但我更喜欢 Python 的小写字母加下划线命名风格。




  • 没有好用的包管理器,Golang 官方也没有推荐最佳的包管理方案,目前公认的比较好用的有 Godeps, Govendor 及 Glide,而 Python 的包管理器 pip 已形成自己的一套标准。




  • 多行字符串的变量声明需要用反引号(`),Python 里是三个双引号("""),参考http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go




  • Golang 中的类型匹配是很严格的,不同的类型之间通常需要手动转换,所以在字符串拼接时往往需要对整型进行显式转换,如 fmt.Println("num: " + strconv.Itoa(1))



  • Golang 语言语法里的语法糖并不多,如在 Python 中很流行的 map, reduce, range 等,在 Golang 里都没有得到支持。


另外,推荐阅读 Golang 新手开发者要注意的陷阱和常见错误


学习资料推荐


建议先把 Go 的官方文档过一遍,主要有以下几项:



官方文档看完后,基本也算入门了,这时候可以看看 Go 的示例代码,或者去 Project Euler 刷刷题。


当然也可以去知乎看看大牛们都是如何学习的,链接 https://www.zhihu.com/question/23486344


总结


虽然 Go 有很多被诟病的地方,比如 GC 和对错误的处理方式,但没有任何语言是完美的,从实用角度来讲,Go 有着不输于 Python 的开发效率,完善的第三方工具,以及强大的社区支持,这些就足够了。


相关链接:

https://golang.org/doc/

https://talks.golang.org/2012/splash.article

https://www.zhihu.com/question/21409296

https://www.zhihu.com/question/23486344

http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go

http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/

http://www.oschina.net/translate/go-at-google-language-design-in-the-service-of-software-engineering




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(II): 开发环境搭建

文章分享Cloudinsight 发表了文章 • 0 个评论 • 1554 次浏览 • 2016-10-12 15:44 • 来自相关话题

Authors: startover

Authors: startover





上一篇文章我们已经对 Golang 有了初步的了解,这篇主要介绍如何在 Ubuntu 14.04 上搭建 Golang 开发环境。


安装 Golang


这里就按照官方文档进行安装即可,如下:



  • 下载并解压安装包到指定目录


$ wget https://storage.googleapis.com ... ar.gz
$ tar -C /usr/local -xzf go1.6.3.linux-amd64.tar.gz


  • 设置 PATH


$ echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
$ source ~/.bashrc


  • 验证安装


$ go version
go version go1.6.3 linux/amd64

环境变量设置


$ echo "export GOROOT=/usr/local/go" >> ~/.bashrc
$ echo "export GOPATH=$HOME/go" >> ~/.bashrc
$ source ~/.bashrc

其中,GOROOT 为 Golang 的安装目录,只有当 Golang 安装到除 /usr/local 之外的路径时需要设置,反之则不用设置,GOPATH 是 Golang 的开发目录,详细可参考官方文档


开发工具


工欲善其事,必先利其器,作为一名伪 VIMer,这里主要介绍下如何在 Vim 下配置 Golang 开发环境。


由于之前一直使用 k-vim 作为 Python 开发环境,而 k-vim 已经集成了当前使用最为广泛的用于搭建 Golang 开发环境的 vim 插件 vim-go,只是默认没有开启,需要我们手动进行相关设置。


k-vim 中开启 Golang 语言的支持,非常简单,如下:



  • 修改 ~/.vimrc.bundles(开启 golang 支持,并修改 vim-go 的默认配置,增加快捷键配置等)。


let g:bundle_groups=['python', 'javascript', 'markdown', 'html', 'css', 'tmux', 'beta', 'json', 'golang']

" vimgo {{{
let g:go_highlight_functions = 1
let g:go_highlight_methods = 1
let g:go_highlight_structs = 1
let g:go_highlight_operators = 1
let g:go_highlight_build_constraints = 1

let g:go_fmt_fail_silently = 1
let g:go_fmt_command = "goimports"
let g:syntastic_go_checkers = ['golint', 'govet', 'errcheck']

" vim-go custom mappings
au FileType go nmap <Leader>s <Plug>(go-implements)
au FileType go nmap <Leader>i <Plug>(go-info)
au FileType go nmap <Leader>gd <Plug>(go-doc)
au FileType go nmap <Leader>gv <Plug>(go-doc-vertical)
au FileType go nmap <leader>r <Plug>(go-run)
au FileType go nmap <leader>b <Plug>(go-build)
au FileType go nmap <leader>t <Plug>(go-test)
au FileType go nmap <leader>c <Plug>(go-coverage)
au FileType go nmap <Leader>ds <Plug>(go-def-split)
au FileType go nmap <Leader>dv <Plug>(go-def-vertical)
au FileType go nmap <Leader>dt <Plug>(go-def-tab)
au FileType go nmap <Leader>e <Plug>(go-rename)
au FileType go nnoremap <leader>gr :GoRun %<CR>
" }}}



  • 在 Vim 内执行 :PlugInstall,安装 vim-go




  • 在 Vim 内执行 :GoInstallBinaries,下载并安装 vim-go 依赖的二进制工具,goimportsgolint 等。



  • 安装 gotags,使 tagbar 配置生效。


$ go get -u github.com/jstemmer/gotags

我们来看一下最终效果:


Image of Golang Environment in Vim


编写第一个程序


进入工作目录,新建文件 hello.go,如下:


$ cd $GOPATH
$ vim hello.go
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

运行程序:


$ go run hello.go
Hello, World!



本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(I): Go 之初体验

文章分享Cloudinsight 发表了文章 • 3 个评论 • 1517 次浏览 • 2016-10-12 15:27 • 来自相关话题

Authors: startover

Authors: startover





Go 语言简介


Go,又称 golang,是 Google 开发的一种静态强类型,编译型,并发型,并具有垃圾回收功能的编程语言。


Go 语言于2009年11月正式宣布推出,自2012年发布1.0,最新稳定版1.7。目前,Go的相关工具和生态已逐渐趋于完善,也不乏重量级项目,如 Docker, Kubernetes, Etcd, InfluxDB 等。


Go 语言能解决什么样的问题


同绝大多数通用型编程语言相比,Go 语言更多的是为了解决我们在构建大型服务器软件过程中所遇到的软件工程方面的问题而设计的。乍看上去,这么讲可能会让人感觉 Go 非常无趣且工业化,但实际上,在设计过程中就着重于清晰和简洁,以及较高的可组合性,最后得到的反而会是一门使用起来效率高而且很有趣的编程语言,很多程序员都会发现,它有极强的表达力而且功能非常强大。


总结为以下几点:



  • 清晰的依赖关系

  • 清晰的语法

  • 清晰的语义

  • 偏向组合而不是继承

  • 提供简单的编程模型(垃圾回收、并发)

  • 强大的内置工具(gofmt、godoc、gofix等)


建议有兴趣的同学看看 Go在谷歌:以软件工程为目的的语言设计


Go 语言相对 Python 有哪些优势


这里引用一段知乎上某大牛的回答,如下:




  • 部署简单。Go 编译生成的是一个静态可执行文件,除了 glibc 外没有其他外部依赖。这让部署变得异常方便:目标机器上只需要一个基础的系统和必要的管理、监控工具,完全不需要操心应用所需的各种包、库的依赖关系,大大减轻了维护的负担。这和 Python 有着巨大的区别。由于历史的原因,Python 的部署工具生态相当混乱【比如 setuptools, distutils, pip, buildout 的不同适用场合以及兼容性问题】。官方 PyPI 源又经常出问题,需要搭建私有镜像,而维护这个镜像又要花费不少时间和精力。




  • 并发性好。Goroutine 和 channel 使得编写高并发的服务端软件变得相当容易,很多情况下完全不需要考虑锁机制以及由此带来的各种问题。单个 Go 应用也能有效的利用多个 CPU 核,并行执行的性能好。这和 Python 也是天壤之比。多线程和多进程的服务端程序编写起来并不简单,而且由于全局锁 GIL 的原因,多线程的 Python 程序并不能有效利用多核,只能用多进程的方式部署;如果用标准库里的 multiprocessing 包又会对监控和管理造成不少的挑战【我们用的 supervisor 管理进程,对 fork 支持不好】。部署 Python 应用的时候通常是每个 CPU 核部署一个应用,这会造成不少资源的浪费,比如假设某个 Python 应用启动后需要占用 100MB 内存,而服务器有 32 个 CPU 核,那么留一个核给系统、运行 31 个应用副本就要浪费 3GB 的内存资源。




  • 良好的语言设计。从学术的角度讲 Go 语言其实非常平庸,不支持许多高级的语言特性;但从工程的角度讲,Go 的设计是非常优秀的:规范足够简单灵活,有其他语言基础的程序员都能迅速上手。更重要的是 Go 自带完善的工具链,大大提高了团队协作的一致性。比如 gofmt 自动排版 Go 代码,很大程度上杜绝了不同人写的代码排版风格不一致的问题。把编辑器配置成在编辑存档的时候自动运行 gofmt,这样在编写代码的时候可以随意摆放位置,存档的时候自动变成正确排版的代码。此外还有 gofix, govet 等非常有用的工具。



  • 执行性能好。虽然不如 C 和 Java,但通常比原生 Python 应用还是高一个数量级的,适合编写一些瓶颈业务。内存占用也非常省。


从个人对 Golang 的初步使用来说,体验还是相当不错的,但是也有下面几点需要注意:




  • 驼峰式命名风格(依据首字母大小写来决定其是否能被其他包引用),但我更喜欢 Python 的小写字母加下划线命名风格。




  • 没有好用的包管理器,Golang 官方也没有推荐最佳的包管理方案,目前公认的比较好用的有 Godeps, Govendor 及 Glide,而 Python 的包管理器 pip 已形成自己的一套标准。




  • 多行字符串的变量声明需要用反引号(`),Python 里是三个双引号("""),参考http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go




  • Golang 中的类型匹配是很严格的,不同的类型之间通常需要手动转换,所以在字符串拼接时往往需要对整型进行显式转换,如 fmt.Println("num: " + strconv.Itoa(1))



  • Golang 语言语法里的语法糖并不多,如在 Python 中很流行的 map, reduce, range 等,在 Golang 里都没有得到支持。


另外,推荐阅读 Golang 新手开发者要注意的陷阱和常见错误


学习资料推荐


建议先把 Go 的官方文档过一遍,主要有以下几项:



官方文档看完后,基本也算入门了,这时候可以看看 Go 的示例代码,或者去 Project Euler 刷刷题。


当然也可以去知乎看看大牛们都是如何学习的,链接 https://www.zhihu.com/question/23486344


总结


虽然 Go 有很多被诟病的地方,比如 GC 和对错误的处理方式,但没有任何语言是完美的,从实用角度来讲,Go 有着不输于 Python 的开发效率,完善的第三方工具,以及强大的社区支持,这些就足够了。


相关链接:

https://golang.org/doc/

https://talks.golang.org/2012/splash.article

https://www.zhihu.com/question/21409296

https://www.zhihu.com/question/23486344

http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go

http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/

http://www.oschina.net/translate/go-at-google-language-design-in-the-service-of-software-engineering




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

golang 特性简介

文章分享sheepbao 发表了文章 • 0 个评论 • 1016 次浏览 • 2017-01-22 16:37 • 来自相关话题

golang 特性简介

by sheepbao

主要大概介绍go语言的历史和特性,简单的入门。

来历

很久以前,有一个IT公司,这公司有个传统,允许员工拥有20... 查看全部

golang 特性简介


by sheepbao


主要大概介绍go语言的历史和特性,简单的入门。


来历


很久以前,有一个IT公司,这公司有个传统,允许员工拥有20%自由时间来开发实验性项目。在2007的某一天,公司的几个大牛,正在用c++开发一些比较繁琐但是核心的工作,主要包括庞大的分布式集群,大牛觉得很闹心,后来c++委员会来他们公司演讲,说c++将要添加大概35种新特性。这几个大牛的其中一个人,名为:Rob Pike,听后心中一万个xxx飘过,“c++特性还不够多吗?简化c++应该更有成就感吧”。于是乎,Rob Pike和其他几个大牛讨论了一下,怎么解决这个问题,过了一会,Rob Pike说要不我们自己搞个语言吧,名字叫“go”,非常简短,容易拼写。其他几位大牛就说好啊,然后他们找了块白板,在上面写下希望能有哪些功能(详见文尾)。接下来的时间里,大牛们开心的讨论设计这门语言的特性,经过漫长的岁月,他们决定,以c语言为原型,以及借鉴其他语言的一些特性,来解放程序员,解放自己,然后在2009年,go语言诞生。


思想


Less can be more


大道至简,小而蕴真


让事情变得复杂很容易,让事情变得简单才难


深刻的工程文化


优点



  1. 自带gc。

  2. 静态编译,编译好后,扔服务器直接运行。

  3. 简单的思想,没有继承,多态,类等。

  4. 丰富的库和详细的开发文档。

  5. 语法层支持并发,和拥有同步并发的channel类型,使并发开发变得非常方便。

  6. 简洁的语法,提高开发效率,同时提高代码的阅读性和可维护性。

  7. 超级简单的交叉编译,仅需更改环境变量。(花了我两天时间编译一个imagemagick到arm平台)

  8. 内含完善、全面的软件工程工具。Go语言自带的命令和工具相当地强大。通过它们,我们可以很轻松地完成Go语言程序的获取、编译、测试、安装、运行、运行分析等一系列工作,这几乎涉及了开发和维护一个软件的所有环节。


hello


package main

func main(){
println("hello, sewise")
}

type


主要讲讲特有的类型,其他基本类型不做介绍


slice


切片:可以理解为动态数组,类似c++的vector
声明一个slice


    var slice []T
如:
var ints []int

slice的追加


    ints=append(ints,1)
ints=append(ints,2,3,4,5)

slice的截取


    newInts1:=ints[2:3]
newInts2:=ints[2:]
newInts3:=ints[:4]

map


字典:键值对


    var json map[string]string

interface


接口:方法的集合,是一种合约
栗子:
声明一个bird接口


    var bird interface{
fly()
}

声明一个hen对象(实现bird接口)


    type hen struct {
weight int
hasFeather bool
}

func (h hen)fly(){
fmt.Println("iI can fly")
}

type func (h hen)eat(){
h.weight++
fmt.Println("yes, I can eat")
}

声明一个pig对象(未实现bird接口,因为pig不会fly)


    type pig struct {
age int
weignt int
hasFeather bool
}

func (p pig)run(){
fmt.Println("I can run")
}

func (p pig)eat(){
p.weight += 100
fmt.Println("Yes, I can eat so much")
}

func (p pig)sleep(){
fmt.Println("I slept all my life")
}

// pig can't fly

channel


通道:轻量集队列,传递某种类型的值的通道


    var ch chan int
ch=make(chan int,1)

往ch写入一个数据


    ch<-8888

从ch读取数据


    out:=<-ch

特性:
channel是有长度的,当channel的缓冲为满时,再往里写入就会阻塞,当channel的缓冲为空时,从channel读就会阻塞


package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan int)
fmt.Println("ch len:", len(ch))
go func() {
// 往缓冲满的channel里写数据(阻塞)
// ch <- 1
// 从缓冲为空的channel里读数据(阻塞)
<-ch
fmt.Println("I am in minor goroutine")
}()
fmt.Println("I am in main goroutine")
time.Sleep(2 * time.Second)
}

当长度为0是,就是不带缓冲的channel
长度大于0,就是带缓冲的channel


并发


关键字:go 启动go程
一个普通的函数或方法调用前加上关键字go,即可启动一个goroutine


    go func(){
fmt.Println("start func")
time.Sleep(120*time.Second)
}()

竞争条件检测
-race
race.go


package main

import (
"fmt"
"time"
)

func main() {
a := 1
go func() {
a = 2
}()
a = 3
fmt.Println("a is ", a)

time.Sleep(2 * time.Second)
}

检测:执行go run -race race.go


a is  3
==================
WARNING: DATA RACE
Write at 0x00c420072188 by goroutine 6:
main.main.func1()
/Users/bao/program/go/gowork/hello/src/research/race.go:11 +0x3b

Previous write at 0x00c420072188 by main goroutine:
main.main()
/Users/bao/program/go/gowork/hello/src/research/race.go:13 +0x9f

Goroutine 6 (running) created at:
main.main()
/Users/bao/program/go/gowork/hello/src/research/race.go:12 +0x8e
==================
Found 1 data race(s)

结果分析:
goroutine6运行到第11行和main goroutine运行到13行的时候触发竞争了。而且goroutine6是在第12行的时候产生的。


package


包的管理,关键字importGOPATH


gopath


gopath是一个路径列表,存放go项目工程
GOPATH文件目录结构


├── bin  二进制文件目录
├── pkg 编译好的库文件目录
└── src 源码目录

平常项目的目录结构


├── bin  二进制文件目录
├── pkg 编译好的库文件目录
└── src 源码目录
├── main 入口函数目录
└── vendor 当前项目的库目录
└── sheepbao.com
└── glog

import


比如上面的项目,我要在main.go引入glog


package main

// 引入glog包
import "sheepbao.com/glog"

func main(){
glog.Println("test")
}

go的工程工具简介


test


go的命令工具 test,用来做测试


单元测试


go test
只测试函数名被它正确匹配的测试函数
go test -v -run="French|Canal"


栗子:
add.go


package test

func addOne(i int) int {
return i + 1
}

add_test.go


package test

import "testing"

func TestAddOne(t *testing.T) {
result := addOne(1)
if result != 2 {
t.Error("1+1!=2")
}
}

bao@baoMac test$ go test -v .
=== RUN TestAddOne
--- PASS: TestAddOne (0.00s)
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/test 0.006s

基准测试


go test -bench=.
内存的分配情况
go test -bench=FuncName -benchmem
栗子:
stringsCon.go


package bench

import (
"fmt"
)

func Sprintf(s1, s2, s3 string) string {
return fmt.Sprintf("%s%s%s", s1, s2, s3)
}

func AddString(s1, s2, s3 string) string {
return s1 + s2 + s3
}

stringCon_test.go


package bench

import "testing"

var (
s1 = "make it run!"
s2 = "make it right!"
s3 = "make it fast!"
)

func BenchmarkSprintf(b *testing.B) {
for i := 0; i < b.N; i++ {
Sprintf(s1, s2, s3)
}
}

func BenchmarkAddString(b *testing.B) {
for i := 0; i < b.N; i++ {
AddString(s1, s2, s3)
}
}

go test -bench=.


bao@baoMac bench$ go test -bench=.
testing: warning: no tests to run
BenchmarkSprintf-4 5000000 349 ns/op
BenchmarkAddString-4 20000000 61.7 ns/op
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/bench 3.414s

样本测试


package et

import (
"fmt"
)

func ExampleHello() {
fmt.Println("hello, sewise")
// Output: hello, sewise
}

bao@baoMac example$ go  test -v .
=== RUN ExampleHello
--- PASS: ExampleHello (0.00s)
PASS
ok _/Users/bao/program/go/gowork/hello/src/research/example 0.006s

如果把上面的// Output: hello, sewise改为// Output: hello, sewis
则样本测试不能通过


bao@baoMac example$ go  test -v .
=== RUN ExampleHello
--- FAIL: ExampleHello (0.00s)
got:
hello, sewise
want:
hello, sewis
FAIL
exit status 1
FAIL _/Users/bao/program/go/gowork/hello/src/research/example 0.006s

pprof


go的命令工具 pprof,用来性能分析(内存使用,泄露和cpu消耗)
go tool pprof



可视化(原是svg文件,下图为截图):


image_1b72f233avto14d7on4h3nlm51g.png-129.8kB



可视化(原是svg文件,下图为截图:


image_1b72euk7b1knr1d1n1ugq2pe19kim.png-176.7kB


go tool pprof --text http://localhost:6060/debug/pprof/heap


go命令教程


资料


http://www.csdn.net/article/2012-07-04/2807113-less-is-exponentially-more


http://www.jianshu.com/p/91e40c3e3acb?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


http://smallsoho.com/2016/11/20/Go简明教程.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io


大牛真身


最大牌的当属B和C语言设计者、Unix和Plan 9创始人、1983年图灵奖获得者Ken Thompson,这份名单中还包括了Unix核心成员Rob Pike(go语言之父)、java HotSpot虚拟机和js v8引擎的开发者Robert Griesemer、Memcached作者Brad Fitzpatrick,等等。


功能



  • 规范的语法(不需要符号表来解析)

  • 垃圾回收(独有)

  • 无头文件

  • 明确的依赖

  • 无循环依赖

  • 常量只能是数字

  • int和int32是两种类型

  • 字母大小写设置可见性(letter case sets visibility)

  • 任何类型(type)都有方法(不是类型)

  • 没有子类型继承(不是子类)

  • 包级别初始化以及明确的初始化顺序

  • 文件被编译到一个包里

  • 包package-level globals presented in any order

  • 没有数值类型转换(常量起辅助作用)

  • 接口隐式实现(没有“implement”声明)

  • 嵌入(不会提升到超类)

  • 方法按照函数声明(没有特别的位置要求)

  • 方法即函数

  • 接口只有方法(没有数据)

  • 方法通过名字匹配(而非类型)

  • 没有构造函数和析构函数

  • postincrement(如++i)是状态,不是表达式

  • 没有preincrement(i++)和predecrement

  • 赋值不是表达式

  • 明确赋值和函数调用中的计算顺序(没有“sequence point”)

  • 没有指针运算

  • 内存一直以零值初始化

  • 局部变量取值合法

  • 方法中没有“this”

  • 分段的堆栈

  • 没有静态和其它类型的注释

  • 没有模板

  • 内建string、slice和map

  • 数组边界检查

Python 程序员的 Golang 学习指南(IV): 包管理篇

文章分享Cloudinsight 发表了文章 • 2 个评论 • 635 次浏览 • 2016-10-19 19:08 • 来自相关话题

Authors: startover

Authors: startover





第一篇文章我们有提到,Golang 官方并没有推荐最佳的包管理方案,对于像我这样习惯了 Python 包管理的开发者,自然还是希望有像 pip 一样好用的工具,帮助我们进行依赖管理,下面就让我们对 Golang 的包管理机制一探究竟。


Golang 包管理机制


Go 语言的包管理系统是去中心化的,我们可以通过 go get 命令获取存放在远程仓库的代码协议。实际上,go get 支持以下 VCS 协议:
































名称 主命令 说明
Mercurial hg Mercurial是一种轻量级分布式版本控制系统,采用Python语言实现,易于学习和使用,扩展性强。
Git git Git最开始是Linux Torvalds为了帮助管理 Linux 内核开发而开发的一个开源的分布式版本控制软件。但现在已被广泛使用。它是被用来进行有效、高速的各种规模项目的版本管理。
Subversion svn Subversion是一个版本控制系统,也是第一个将分支概念和功能纳入到版本控制模型的系统。但相对于Git和Mercurial而言,它只算是传统版本控制系统的一员。
Bazaar bzr Bazaar是一个开源的分布式版本控制系统。但相比而言,用它来作为VCS的项目并不多。

比如,我们现在需要获取 godep 这个项目,可以执行如下命令:


$ go get github.com/tools/godep

需要指出的是,go get 实际上执行了两个步骤:1. 下载源码包;2. 执行 go install,如果只下载不安装,则需要指定 -d 参数,如下:


$ go get -d github.com/tools/godep

除了 go get,Go 语言还提供了一个 Workspace 的机制,即通过设定 GOPATH 环境变量,指定除了 GOROOT 所指定的目录之外,Go 代码所在的位置(也就是 Workspace 的位置)。 一般来说,GOPATH 目录下会包含 pkg、src 和 bin 三个子目录,这三个目录各有用处。



  • bin 目录用于放置编译好的可执行文件,为了使得这里的可执行文件可以方便的运行, 可在 shell 中设置 PATH 环境变量。

  • src 目录用于放置代码源文件,在进行 import 时,是使用这个位置作为根目录的。自己编写的代码也应该放在这下面。

  • pkg 用来放置安装的包的链接对象(Object)的。这个概念有点类似于链接库,Go 会将编译出的可连接库放在这里, 方便编译时链接。不同的系统和处理器架构的对象会在 pkg 存放在不同的文件夹中。


Golang 包管理现状


显然,通过 go getWorkspace 的方式并不足以解决项目依赖和版本依赖的问题,主要有以下几点:



  1. 第三方包的版本控制。如果没有明确指定依赖的第三方包的版本,团队开发很容易导入不一样的版本,导致项目无法正常运行。

  2. 第三方包没有内容安全审计,很容易引入代码 Bug,这是泛中心化包管理普遍存在的问题。

  3. 依赖的完整性无法校验,程序编译时无法保障百分百成功。


因此,我们必须借助第三方工具来解决这些问题。


第三方解决方案


这里我从官方推荐包管理工具中挑选了几个比较常用的工具:Godep, Govendor 以及 Glide,作下简单介绍。


Godep



  • godep save


这个命令做了以下几件事:




  1. 查找项目中所用到的所有的第三方包。

  2. 在项目目录下创建 Godeps 目录,Godeps/Godeps.json 是依赖文件,包括了 go 的版本,用到的第三方包的引入路径,版本号等信息,json 文件需要一并加入到版本控制里。

  3. 所有依赖的第三方包的代码会被拷贝到 vendor/ 下,并且移除了 .git 这样的版本控制信息。




  • godep restore


当下载别人发布的项目时,如果下载的项目中只有 Godeps.json 文件,而没有包含第三方包,则可以使用 godep restore 这个命令将所有的依赖包下载到 $GOPATH 目录下,而不用一个一个去 go get,还是很方便的。


Govendor



  • govendor init


执行 govendor init 会在根目录下生成一个 vendor 文件夹,以及 vendor/vendor.json,其中 vendor.json 类似 godep 工具中的描述文件版本的功能。



  • govendor add +external


执行 govendor add +external 会将所有依赖的第三方包的代码拷贝到 vendor 文件夹下,并且移除了 .git 这样的版本控制信息,测试所需依赖以及依赖项目的测试文件。与 godep save 的功能类似。



  • govendor fetch


执行 govendor fetch 新增的第三方包直接被 get 到根目录的 vendor 文件夹下,不会与其它的项目混用第三方包,完美避免了多个项目同用同一个第三方包的不同版本问题。


这样,我们只需对 vendor/vendor.json 进行版本控制,即可对第三包依赖关系进行控制。


Glide



  • glide init


执行 glide initglide create 会在项目根目录下生成一个 glide.yaml,这个文件用来记录项目用到的第三方包的依赖关系,并支持编辑修改。



  • glide install


执行 glide install,会把所有依赖的第三方包都下载到 vendor 文件夹下,并且会在 glide.yaml 中添加所有依赖的第三方包名称,以及在 glide.lock 文件中记录具体的版本管理信息。


总结


上面我们分别对 Godep, Govendor 以及 Glide 这三种工具做了简单的介绍,对于 Python 开发者,个人还是比较认同 Govendor 的方式,因为其很容易实现类似 Virtualenv 的模式,从而实现不同程序使用不同版本依赖的目的。


当然,如果你是 Node.js 的开发者,可能对于 Godep 有更加熟悉的感觉,而对于 Ruby 开发者,gom 会让你感到更加亲切。


因此,针对第三方包管理工具的选择,现阶段还完全交由开发者做裁定,这里就“仁者见仁,智者见智”了。


相关链接:

http://www.infoq.com/cn/articles/golang-package-management

https://io-meter.com/2014/07/30/go's-package-management/

https://github.com/golang/go/wiki/PackageManagementTools




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(III): 入门篇

文章分享Cloudinsight 发表了文章 • 0 个评论 • 1575 次浏览 • 2016-10-14 15:39 • 来自相关话题

Authors: startover

Authors: startover





基础语法


类型和关键字



  • 类型


// 基础类型
布尔类型: bool
整型: int8,uint8,int16,uint16,int32,uint32,int64,uint64,int,rune,byte,complex128, complex64,其中,byte 是 int8 的别名
浮点类型: float32 、 float64
复数类型: complex64 、 complex128
字符串: string
字符类型: rune(int32的别名)
错误类型: error

// 复合类型
指针(pointer)
数组(array)
切片(slice)
字典(map)
通道(chan)
结构体(struct)
接口(interface)


  • 关键字


break        default      func         interface    select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

变量


Go 同其他语言不同的地方在于变量的类型在变量名的后面,不是 int a,而是 a int。至于为什么这么定义,Go 的官方博客有给出解释,有兴趣的可以参考下。


变量定义语法如下:


var a int
a = 2

// 或者
a := 2

// 同时定义多个变量
var (
a int
b bool
)

// 同时给多个变量赋值
a, b := 2, true

操作符


+    &     +=    &=     &&    ==    !=    (    )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^=

控制结构


Go 语言支持如下的几种流程控制语句:



  • 条件语句,对应的关键字为 if、else 和 else if;

  • 选择语句,对应的关键字为 switch、case 和 select;

  • 循环语句,对应的关键字为 for 和 range;

  • 跳转语句,对应的关键字为 goto。


值得一提的是,Go 语言并不支持 do 或者 while 关键字,而是对 for 关键字做了增强,以实现类似的效果,如下:


for {
// 实现无限循环,慎用!
}

常用内置函数



  • len:计算(字符串,数组或者切片,map)长度

  • cap:计算(数组或者切片,map)容量

  • close:关闭通道

  • append:追加内容到切片

  • copy:拷贝数组/切片内容到另一个数组/切片

  • delete:用于删除 map 的元素


array, slice 和 map


// array
a := [3]int{ 1, 2, 3 } // 等价于 a := [...]int{ 1, 2, 3 }

// slice
s := make([]int , 3) // 创建一个长度为 3 的 slice
s := append(s, 1) // 向 slice 追加元素
s := append(s, 2)

// map
m := make(map[string]int) // 使用前必须先初始化
m["golang"] = 7

关于 array, slice 和 map 的更多惯用法,有一篇文章介绍的挺详细,有兴趣的可以看看。


函数


Go 语言的函数有如下特性:



  • 不定参数


由于 Go 语言不支持函数重载(具体原因见 Go Language FAQ),但我们可以通过不定参数实现类似的效果。


func myfunc(args ...int) {
// TODO
}

// 可通过如下方式调用
myfunc(2)
myfunc(1, 3, 5)


  • 多返回值


与 C、C++ 和 Java 等开发语言的一个极大不同在于,Go 语言的函数或者成员的方法可以有多
个返回值,这个特性能够使我们写出比其他语言更优雅、更简洁的代码。


func (file *File) Read(b []byte) (n int, err error)

// 我们可以通过下划线(_)来忽略某个返回值
n, _ := f.Read(buf)


  • 匿名函数


匿名函数是指不需要定义函数名的一种函数实现方式,它并不是一个新概念,最早可以回溯
到 1958 年的 Lisp 语言。但是由于各种原因,C 和 C++ 一直都没有对匿名函数给以支持,其他的各
种语言,比如 JavaScript、C# 和 Objective-C 等语言都提供了匿名函数特性,当然也包含Go语言。


匿名函数由一个不带函数名的函数声明和函数体组成,如下:


func(a, b int) bool {
return a < b
}

匿名函数可以直接赋值给一个变量或者直接执行:


f := func(a, b int) bool {
return a < b
}

func(a, b int) bool {
return a < b
}(3, 4) // 花括号后直接跟参数列表表示函数调用


  • 闭包


闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者
任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块(由于自由变量包含
在代码块中,所以这些自由变量以及它们引用的对象没有被释放)为自由变量提供绑定的计算环
境(作用域)。


Go 的匿名函数就是一个闭包。我们来看一个例子:


package main

import "fmt"

func main() {
j := 5
a := func() func() {
i := 10
return func() {
fmt.Printf("i, j: %d, %d\n", i, j)
}
}()
a()
j *= 2
a()
}

程序输出如下:


i, j: 10, 5
i, j: 10, 10

错误处理


Go 语言追求简洁优雅,所以,Go 语言不支持传统的 try...catch...finally 这种异常,因为 Go 语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在 Go 语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下,也就是说,遇到真正的异常的情况下(比如除数为0了),才使用 Go 中引入的Exception处理:defer, panic, recover。


用法如下:


package main

import "fmt"

func main() {
defer func() {
fmt.Println("recovered:", recover())
}()
panic("not good")
}

关于 Go 语言的错误处理机制和传统的 try...catch...finally 异常机制孰优孰劣,属于仁者见仁,智者见智,这里不做赘速。有兴趣的同学可以去看看知乎上的讨论:Go 语言的错误处理机制是一个优秀的设计吗?


面向对象 -> 一切皆类型


Python 推崇“一切皆对象”,而在 Go 语言中,类型才是一等公民。


我们可以这样定义一个结构体:


type Name struct {
First string
Middle string
Last string
}

同样也可以定义基础类型:


type SimpleName string

还能给任意类型定义方法:


func (s SimpleName) String() string { return string(s) }
// 或者
func (s string) NoWay()

Golang VS Python


最后我们通过几个例子来比较一下 Golang 与 Python 的一些基本用法,如下:


生成器(Generator)



  • Python 版本


def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
yield a

for x in fib(10):
print x

print 'done'


  • Golang 版本


package main

import "fmt"

func fib(n int) chan int {
c := make(chan int)
go func() {
a, b := 0, 1
for i := 0; i < n; i++ {
a, b = b, a+b
c <- a
}
close(c)
}()
return c
}

func main() {
for x := range fib(10) {
fmt.Println(x)
}
}

装饰器(Decorator)



  • Python 版本


from urlparse import urlparse, parse_qs
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

def auth_required(myfunc):
def checkuser(self):
user = parse_qs(urlparse(self.path).query).get('user')
if user:
self.user = user[0]
myfunc(self)
else:
self.wfile.write('unknown user')
return checkuser

class myHandler(BaseHTTPRequestHandler):
@auth_required
def do_GET(self):
self.wfile.write('Hello, %s!' % self.user)

if __name__ == '__main__':
try:
server = HTTPServer(('localhost', 8080), myHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()


  • Golang 版本


package main

import (
"fmt"
"net/http"
)

var hiHandler = authRequired(
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))
},
)

func authRequired(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.FormValue("user") == "" {
http.Error(w, "unknown user", http.StatusForbidden)
return
}
f(w, r)
}
}

func main() {
http.HandleFunc("/hi", hiHandler)
http.ListenAndServe(":8080", nil)
}

猴子补丁(Monkey patching)



  • Python 版本


import urllib

def say_hi(usr):
if auth(usr):
print 'Hi, %s' % usr
else:
print 'unknown user %s' % usr

def auth(usr):
try:
auth_url = 'localhost'
r = urllib.urlopen(auth_url + '/' + usr)
return r.getcode() == 200
except:
return False

def sayhitest():
# Test authenticated user
globals()['auth'] = lambda x: True
say_hi('John')

# Test unauthenticated user
globals()['auth'] = lambda x: False
say_hi('John')

if __name__ == '__main__':
sayhitest()


  • Golang 版本


package main

import (
"fmt"
"net/http"
)

func sayHi(user string) {
if !auth(user) {
fmt.Printf("unknown user %v\n", user)
return
}
fmt.Printf("Hi, %v\n", user)
}

var auth = func(user string) bool {
authURL := "localhost"
res, err := http.Get(authURL + "/" + user)
return err == nil && res.StatusCode == http.StatusOK
}

func testSayHi() {
auth = func(string) bool { return true }
sayHi("John")

auth = func(string) bool { return false }
sayHi("John")
}

func main() {
testSayHi()
}

相关链接:

https://blog.golang.org/gos-declaration-syntax

https://se77en.cc/2014/06/30/array-slice-map-and-set-in-golang/

https://golang.org/doc/faq#overloading

https://www.zhihu.com/question/27158146

https://talks.golang.org/2013/go4python.slide




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注,及时获取最新文章~

Python 程序员的 Golang 学习指南(II): 开发环境搭建

文章分享Cloudinsight 发表了文章 • 0 个评论 • 1554 次浏览 • 2016-10-12 15:44 • 来自相关话题

Authors: startover

Authors: startover





上一篇文章我们已经对 Golang 有了初步的了解,这篇主要介绍如何在 Ubuntu 14.04 上搭建 Golang 开发环境。


安装 Golang


这里就按照官方文档进行安装即可,如下:



  • 下载并解压安装包到指定目录


$ wget https://storage.googleapis.com ... ar.gz
$ tar -C /usr/local -xzf go1.6.3.linux-amd64.tar.gz


  • 设置 PATH


$ echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
$ source ~/.bashrc


  • 验证安装


$ go version
go version go1.6.3 linux/amd64

环境变量设置


$ echo "export GOROOT=/usr/local/go" >> ~/.bashrc
$ echo "export GOPATH=$HOME/go" >> ~/.bashrc
$ source ~/.bashrc

其中,GOROOT 为 Golang 的安装目录,只有当 Golang 安装到除 /usr/local 之外的路径时需要设置,反之则不用设置,GOPATH 是 Golang 的开发目录,详细可参考官方文档


开发工具


工欲善其事,必先利其器,作为一名伪 VIMer,这里主要介绍下如何在 Vim 下配置 Golang 开发环境。


由于之前一直使用 k-vim 作为 Python 开发环境,而 k-vim 已经集成了当前使用最为广泛的用于搭建 Golang 开发环境的 vim 插件 vim-go,只是默认没有开启,需要我们手动进行相关设置。


k-vim 中开启 Golang 语言的支持,非常简单,如下:



  • 修改 ~/.vimrc.bundles(开启 golang 支持,并修改 vim-go 的默认配置,增加快捷键配置等)。


let g:bundle_groups=['python', 'javascript', 'markdown', 'html', 'css', 'tmux', 'beta', 'json', 'golang']

" vimgo {{{
let g:go_highlight_functions = 1
let g:go_highlight_methods = 1
let g:go_highlight_structs = 1
let g:go_highlight_operators = 1
let g:go_highlight_build_constraints = 1

let g:go_fmt_fail_silently = 1
let g:go_fmt_command = "goimports"
let g:syntastic_go_checkers = ['golint', 'govet', 'errcheck']

" vim-go custom mappings
au FileType go nmap <Leader>s <Plug>(go-implements)
au FileType go nmap <Leader>i <Plug>(go-info)
au FileType go nmap <Leader>gd <Plug>(go-doc)
au FileType go nmap <Leader>gv <Plug>(go-doc-vertical)
au FileType go nmap <leader>r <Plug>(go-run)
au FileType go nmap <leader>b <Plug>(go-build)
au FileType go nmap <leader>t <Plug>(go-test)
au FileType go nmap <leader>c <Plug>(go-coverage)
au FileType go nmap <Leader>ds <Plug>(go-def-split)
au FileType go nmap <Leader>dv <Plug>(go-def-vertical)
au FileType go nmap <Leader>dt <Plug>(go-def-tab)
au FileType go nmap <Leader>e <Plug>(go-rename)
au FileType go nnoremap <leader>gr :GoRun %<CR>
" }}}



  • 在 Vim 内执行 :PlugInstall,安装 vim-go




  • 在 Vim 内执行 :GoInstallBinaries,下载并安装 vim-go 依赖的二进制工具,goimportsgolint 等。



  • 安装 gotags,使 tagbar 配置生效。


$ go get -u github.com/jstemmer/gotags

我们来看一下最终效果:


Image of Golang Environment in Vim


编写第一个程序


进入工作目录,新建文件 hello.go,如下:


$ cd $GOPATH
$ vim hello.go
package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

运行程序:


$ go run hello.go
Hello, World!



本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~

Python 程序员的 Golang 学习指南(I): Go 之初体验

文章分享Cloudinsight 发表了文章 • 3 个评论 • 1517 次浏览 • 2016-10-12 15:27 • 来自相关话题

Authors: startover

Authors: startover





Go 语言简介


Go,又称 golang,是 Google 开发的一种静态强类型,编译型,并发型,并具有垃圾回收功能的编程语言。


Go 语言于2009年11月正式宣布推出,自2012年发布1.0,最新稳定版1.7。目前,Go的相关工具和生态已逐渐趋于完善,也不乏重量级项目,如 Docker, Kubernetes, Etcd, InfluxDB 等。


Go 语言能解决什么样的问题


同绝大多数通用型编程语言相比,Go 语言更多的是为了解决我们在构建大型服务器软件过程中所遇到的软件工程方面的问题而设计的。乍看上去,这么讲可能会让人感觉 Go 非常无趣且工业化,但实际上,在设计过程中就着重于清晰和简洁,以及较高的可组合性,最后得到的反而会是一门使用起来效率高而且很有趣的编程语言,很多程序员都会发现,它有极强的表达力而且功能非常强大。


总结为以下几点:



  • 清晰的依赖关系

  • 清晰的语法

  • 清晰的语义

  • 偏向组合而不是继承

  • 提供简单的编程模型(垃圾回收、并发)

  • 强大的内置工具(gofmt、godoc、gofix等)


建议有兴趣的同学看看 Go在谷歌:以软件工程为目的的语言设计


Go 语言相对 Python 有哪些优势


这里引用一段知乎上某大牛的回答,如下:




  • 部署简单。Go 编译生成的是一个静态可执行文件,除了 glibc 外没有其他外部依赖。这让部署变得异常方便:目标机器上只需要一个基础的系统和必要的管理、监控工具,完全不需要操心应用所需的各种包、库的依赖关系,大大减轻了维护的负担。这和 Python 有着巨大的区别。由于历史的原因,Python 的部署工具生态相当混乱【比如 setuptools, distutils, pip, buildout 的不同适用场合以及兼容性问题】。官方 PyPI 源又经常出问题,需要搭建私有镜像,而维护这个镜像又要花费不少时间和精力。




  • 并发性好。Goroutine 和 channel 使得编写高并发的服务端软件变得相当容易,很多情况下完全不需要考虑锁机制以及由此带来的各种问题。单个 Go 应用也能有效的利用多个 CPU 核,并行执行的性能好。这和 Python 也是天壤之比。多线程和多进程的服务端程序编写起来并不简单,而且由于全局锁 GIL 的原因,多线程的 Python 程序并不能有效利用多核,只能用多进程的方式部署;如果用标准库里的 multiprocessing 包又会对监控和管理造成不少的挑战【我们用的 supervisor 管理进程,对 fork 支持不好】。部署 Python 应用的时候通常是每个 CPU 核部署一个应用,这会造成不少资源的浪费,比如假设某个 Python 应用启动后需要占用 100MB 内存,而服务器有 32 个 CPU 核,那么留一个核给系统、运行 31 个应用副本就要浪费 3GB 的内存资源。




  • 良好的语言设计。从学术的角度讲 Go 语言其实非常平庸,不支持许多高级的语言特性;但从工程的角度讲,Go 的设计是非常优秀的:规范足够简单灵活,有其他语言基础的程序员都能迅速上手。更重要的是 Go 自带完善的工具链,大大提高了团队协作的一致性。比如 gofmt 自动排版 Go 代码,很大程度上杜绝了不同人写的代码排版风格不一致的问题。把编辑器配置成在编辑存档的时候自动运行 gofmt,这样在编写代码的时候可以随意摆放位置,存档的时候自动变成正确排版的代码。此外还有 gofix, govet 等非常有用的工具。



  • 执行性能好。虽然不如 C 和 Java,但通常比原生 Python 应用还是高一个数量级的,适合编写一些瓶颈业务。内存占用也非常省。


从个人对 Golang 的初步使用来说,体验还是相当不错的,但是也有下面几点需要注意:




  • 驼峰式命名风格(依据首字母大小写来决定其是否能被其他包引用),但我更喜欢 Python 的小写字母加下划线命名风格。




  • 没有好用的包管理器,Golang 官方也没有推荐最佳的包管理方案,目前公认的比较好用的有 Godeps, Govendor 及 Glide,而 Python 的包管理器 pip 已形成自己的一套标准。




  • 多行字符串的变量声明需要用反引号(`),Python 里是三个双引号("""),参考http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go




  • Golang 中的类型匹配是很严格的,不同的类型之间通常需要手动转换,所以在字符串拼接时往往需要对整型进行显式转换,如 fmt.Println("num: " + strconv.Itoa(1))



  • Golang 语言语法里的语法糖并不多,如在 Python 中很流行的 map, reduce, range 等,在 Golang 里都没有得到支持。


另外,推荐阅读 Golang 新手开发者要注意的陷阱和常见错误


学习资料推荐


建议先把 Go 的官方文档过一遍,主要有以下几项:



官方文档看完后,基本也算入门了,这时候可以看看 Go 的示例代码,或者去 Project Euler 刷刷题。


当然也可以去知乎看看大牛们都是如何学习的,链接 https://www.zhihu.com/question/23486344


总结


虽然 Go 有很多被诟病的地方,比如 GC 和对错误的处理方式,但没有任何语言是完美的,从实用角度来讲,Go 有着不输于 Python 的开发效率,完善的第三方工具,以及强大的社区支持,这些就足够了。


相关链接:

https://golang.org/doc/

https://talks.golang.org/2012/splash.article

https://www.zhihu.com/question/21409296

https://www.zhihu.com/question/23486344

http://stackoverflow.com/questions/7933460/how-do-you-write-multiline-strings-in-go

http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/

http://www.oschina.net/translate/go-at-google-language-design-in-the-service-of-software-engineering




本文章为 Cloudinsight 技术团队工程师原创,更多技术文章可访问 Cloudinsight 技术博客Cloudinsight 为可视化系统监控工具,涵盖 Windows、Linux 操作系统,用 Golang 开发的 Cloudinsight Agent 正式开源了,欢迎 fork,Github:https://github.com/cloudinsight/cloudinsight-agent


golang-for-pythonistas 系列持续更新中,欢迎关注~