Go作为新兴语言,很容易上手,天生支持并发,为多核CPU而生;接近C的执行效率;静态语言;支持垃圾回收。
一. 安装
下载go并设置环境变量
set GOROOT=D:\go #sdk目录
set GOPATH=D:\gowork #工作目录
set PATH=%GOROOT%\bin;%PATH%
二. Hello world
package main // 包名
import "fmt" // 导入Println函数,java/python也是用import关键字
func main() { // { 必须与() 在同一行,否则会编译出错
fmt.Println("hello world") // 与java类似的println()
fmt.Println(os.Args) // 与C不同的是,命令行参数储存在os.Args中
}
编译:
$ go build -o hello.exe hello.go #编译产生可执行文件
$ go run hello.go #该命令会进行编译,链接,运行,没有产生中间文件和可执行文件,直接显示结果
注:Linux下go程序用静态方式链接,无.DYNAMIC段。
-ldflags 设置编译参数:
go build -ldflags "-X main.VERSION=1.0.2 -X 'main.BUILD_TIME=`date`'" objtest.go
程序中只需要声明变量,就可以获取到参数值:
var (
VERSION string
BUILD_TIME string
GO_VERSION string
)
三. 开发工具
IDE工具:eclipse安装goclipse插件,LiteIDE,推荐用Goland。
四. 基础语法
4.1 基础
// 变量定义
var a int
a = 100 // 变量赋值
b := 100 // := 操作符自动推导类型,声明并给变量赋值
// 引号
var str1 string = "hello\nworld" // 双引号(转义)
var str2 rune = 'h' // 单引号
var str3 string = `hello\nworld
hello` // 反引号,不转义且支持多行字符串
// 指针
var p *int // 变量声明,类型后置
var a int = 20
p = &a // 取址,与C语言一致
fmt.Printf("addr:%#04x\n", p)
var brr [5]int // 变量定义不使用会报错:brr declared and not used
var arr = [5]int{1, 2, 3, 4, 5} // 数组
newarr := arr[:] // [:]切片,引用arr数组
// 遍历数组
for i:=0; i<5; i++ {
fmt.Printf("val:%d -- %d\n", i, arr[i]);
}
// 调用模块方法
sub.Substract(10, 20) // 方法名大写作用域为public,小写为private无法外部调用
// 使用关键字go便能启动线程
go hello()
// 匿名函数
b := func(x int,y int)(int,int) {
return x+1,y+2
}
b(2, 3) // 打印3,5
// 不定参数本质上是slice,python为元组
func GetParam(params ... string) {}
// 对象初始化
rect := new(Rect)
rect1 := &Rect{}
rect2 := &Rect{width: 100, height: 200}
4.2 结构体与反射
a. 结构体指针
// 定义结构体,go中无class关键字
type Person1 struct {
Age int
Name string
}
// 定义结构体指针
p := new(Person1)
p.Age = 20 // .操作,非c ->
p.Name = "kettas"
fmt.Printf("Person struct: %v\n", *p) // 输出:Person struct: {20 kettas}
注:slice/map/chan/interface{} 必须初始化后才能使用,未初始化时为nil。
b. 结构体标签
结构体字段可添加标签,方便序列化显示。
import "encoding/json"
type Person2 struct {
Age int `bson:"_id" json:"age"`
Name string `bson:"_name" json:"name"`
}
// 结构体标签
var p1 Person1 = Person1{18, "kettas"}
var p2 Person2 = Person2{20, "sun"}
b, _ := json.Marshal(p1);
fmt.Println("Person1: ", string(b)); // 输出:Person1: {"Age":18,"Name":"kettas"}
b, _ = json.Marshal(p2);
fmt.Println("Person2: ", string(b)); // 输出:Person2: {"age":20,"name":"sun"}
添加标签的字段编码会将字段转化成小写。struct 属性首字母大写解决外部调用的问题,标签解决与外部通过json交换数据时序列化问题。
c. 反射
go很容易实现反射
import "reflect"
// 反射测试
t := reflect.TypeOf(p2)
fmt.Printf("Type:%s Kind:%s\n", t.Name(), t.Kind())
// 遍历结构体属性
for i:=0; i<t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("json")
fmt.Printf("%d %v(%v) tag:%v\n", i+1, field.Name,field.Type.Name(), tag)
}
// 输出
Type:Person2 Kind:struct
1 Age(int) tag:age
2 Name(string) tag:name
4.3 接口
/// http 服务器
// 定义接口
type Phone interface {
call() int
}
// 为了实现接口,需先定义一个struct
type Hello struct {
}
// Hello成员方法ServerHTTP,实现http的 ServeHTTP()接口
func (h Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello!")
}
func httpServ() {
var h Hello
http.ListenAndServe("localhost:4000", h)
}
4.3 管道
// 数组求和
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
// 计算结果发送到 channel c
c <- sum
}
// 管道测试
func channeltest() {
a := []int{1, 2, 7, 8, 10, 5}
c := make(chan int) // 建立无缓冲管道c
go sum(a[:len(a)/2],c) // go关键字启动goroutine,计算前半段10
go sum(a[len(a)/2:],c) // 计算后半段23
x,y := <-c,<-c // 堵塞接收管道c值,并赋值给x,y
fmt.Println(x, y, x+y) // 输出: 23 10 33
}
4.4 foreach语法
// go
for i,v := range a {} // 可省略i,k,用_代替
// java
int a[] = {1,2,3,4};
for(int i : a){ }
// c++11, QT的foreach宏
for(auto i : a){ }
// python
for i in a:
print i