一、安装
1.下载和解压缩
# wget https://storage.googleapis.com/golang/go1.7.1.linux-amd64.tar.gz
# tar -C /usr/local -xzf go1.7.1.linux-amd64.tar.gz
2、添加环境变量
2.1 Add /usr/local/go/bin to the PATH environment variable
在控制台临时设置变量
# export GOROOT=/usr/local/go
# export PATH=$PATH:$GOROOT/bin
在配置文件中 vim /etc/profile 永久设置变量,具体方法问百度。
3、测试环境
# mkdir -p $HOME/go/workspace
# export GOPATH=$HOME/go/workspace
# mkdir $GOPATH/src/hello
# echo "" > $GOPATH/src/hello/hello.go #新增go文件
在hello.go里面的内容
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
使用go tool 编译该项目
# go install hello
# $GOPATH/bin/hello
hello, world
二、go 语法学习
基本类型
bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte // uint8 的别名 rune // int32 的别名 // 代表一个Unicode码 float32 float64 complex64 complex128
这个例子演示了具有不同类型的变量。 同时与导入语句一样,变量的定义“打包”在一个语法块中。
int
,uint
和 uintptr
类型在32位的系统上一般是32位,而在64位系统上是64位。当你需要使用一个整数类型时,你应该首选 int
,仅当有特别的理由才使用定长整数类型或者无符号整数类型。
1、导入包:
1)包使用“”标示 2)包路径/
单独导入
import "fmt"
import "math/rand"
组合导入 1、使用括号组织包 2、,3、包之间换行 4、
import (
"fmt"
"math/rand"
)
2、导出名
只有首字母大写可以被导出
Func Foo()
{
}
Func FOO()
{
}
Func foo()
{
}
Foo 和FOO可以被导出,foo 首字母小写无法导出。
3、函数
3.1 注意类型在变量名 之后 。
func(x int, y int ) int {
return (x + y);
}
3.2 当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略
func(x, y, z int ) int {
return (x + y + z);
}
3.3 可以返回任何数量的返回值
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
3.4 命名返回值 下面代码命名了 x,y int
func split(sum int)(x, y int) {
x = sum * 4 /9
y = sum - x
return
}
4 var 定义变量列表
var 语句定义了一个变量的列表;跟函数的参数列表一样,类型在后面。
var c, python, java bool
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
5、初始化变量
定义变量可以包含初始化值,每个变量对应一个值
var a , b , c string = "hello1","hello2","hello3"
如果初始化变量值是表达式,可以忽略变量类型;变量类型从表达式结果中获得
var a , b , c = "hello1","hello2","hello3"
6、短声明变量 :=
该用法不可以使用在函数外面。在函数中,简洁赋值语句在类型明确的地方,可以用于替换 var
a , b , c := "hello11","hello22","hello33"
7、变量在定义时没有明确初始化,会默认为零值。
数值为0,bool 为 false,string 为 ""(空字符串)
8、类型转换
表达式 T(v),将值 v 转换为类型T ,不通类型转换必须显式转换。
9、常量
const Pi = 3.14
10、for 循环
10.1for 循环并不需要使用括号括起来:初始化语句;循环条件表达式;后置语句;但是循环体必须使用{}括起来。
sum := 0;
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
10.2 for初始化语句和后置语句是可选的
sum := 1
for ; sum < 1000; {
sum += sum
}
11 for 是go 的while
sum := 1
for sum < 1000 {
sum += sum
}
12 死循环
忽略了循环条件,循环就不会结束,因此可以用更简洁的语句表达死循环
for {}
13 if
的便捷表达式
跟 for 一样, if 语句可以在条件之前执行一个简单语句。该语句定义的变量作用域仅在if /else 范围内
if v := math.Pow(3,3); v < 20 {
fmt.Println(v)
} else {
fmt.Println(v)
}
14 switch 的便捷表达式
跟 for 一样, switch 语句可以在条件之前执行一个简单语句。该语句定义的变量作用域仅在switch 范围内
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.", os)
}
switch 分支不需要break,除非以 fallthrough 语句结束,否则分支会自动终止
15 defer
defer 语句会延迟函数的执行直到上层函数返回。
1) 延迟调用的参数会立刻生成,但是在上层函数返回前函数都不会被调用
2)延迟的函数调用被压入一个栈中。当函数返回时, 会按照后进先出的顺序调用被延迟的函数调用。
func main() {
fmt.Println("start")
for i := 0 ; i < 10; i++ {
fmt.Println(i)
}
fmt.Println("done")
}
#./test
start
done
9
8
7
6
5
4
3
2
1
0
16、指针
go没有指针运行符
x, y := 12,13
p := &x
fmt.Println(*p) #即将打印12
p = &y
*p = 21
fmt.Println(y) #即将打印21
17、结构struct
1)声明:
type struName struct{
var1 T1
var2 T2
}
2)调用构造函数 struName{var1,var2....}
3)访问方式 .成员变量
type Vertex struct {
x int
y int
}
func main() {
stru := Vertex{1 ,2}
fm.Println(stru) #输出:{1,2}
fmt.Println(stru.x, stru.y) #输出:1 2
p := &stru
fm.Println(*p) #输出:{1,2}
fmt.Println(p.x, p.y) #输出:1 2
}
18、数组
var a [2]string
a[0] = "hello"
a[1] = "world"
19、slice
19.1 一个slice 会指向一个有序列的值,并且包含长度信息。形如: []T
ss := [][]string{
[]string{"hello0","world0"},
[]string{"hello1","world1"},
[]string{"hello2","world2"},
}
for i := 0; i< len(ss); i++ {
fmt.Println(ss[i][0],ss[i][1])
}
结果
#./test
hello0 world0
hello1 world1
hello2 world2
19.2 对slice切片
slice可以重新切片,创建一个新的slice值指向相同的数组。形如:s[lo:hi]
,表示从lo到hi-1的slice元素,含前端,不包含后端。s[lo, lo]
是空值,s[lo,lo+1]
有1个元素
19.3 make 函数
make:分配一个全是零值的数组并且返回一个slice指向这个数组。形如:s := make([]string , 3)
注意slice有长度和容量 ,长度:len(s),容量:cap(s)
s := make([]string, 0 , 5)
len(s) :返回0
cap(s) ::返回5
19.4 slice的零值为nil
20 range
for 循环的range 格式可以对slice 或者map 进行迭代,当使用for循环遍历一个slice时,每次迭代range 将返回两个值:下标和值
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
输出
# ./test
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128
for range 的简略写法
func main() {
pow := make([]int, 10)
//只需要索引,去掉", value"
for i := range pow {
pow[i] = 1 << uint(i)
}
//只需要治,赋值给_忽略序号
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
21 map--映射值到键
map在使用之前必须使用make来创建,否则为空map,值为nil,不能对其赋值
var m map[string]int
func main() {
m = make(map[string]int)
m["Bell"] = 12 //插入一个元素
fmt.Println("Bell' age is %d", m["Bell"]) //获取一个元素
m["Bell"] = 15 //修改一个元素
m2 := map[string]int {
"Alice":13,
}
elem , ok := m2["Alice"] //使用双赋值检测某个键存在,存在 ok为true,否则为false,并且elem是map元素类型的零值
if ok {
fmt.Println("Alice' age is %d", elem)
}
delete(m2, "Alice") //删除一个元素
elem, ok = m2["Alice"]
if ok {
fmt.Println("Alice' age is %d", elem)
}
22 函数值--函数作为函数参数传递或者作为返回值
func compute(fn func(float64, float64) float64) float64 {
return fn(float64(3), float64(4)) //调用参数 -fn
}
func add(x ,y float64) float64 {
return x + y
}
func getfunc() func(float64, float64) float64 {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
return hypot //返回函数
}
func main() {
hypot := getfunc()
fmt.Println(compute(hypot)) //hypot是参数
fmt.Println(compute(math.Pow)) //math.Pow是参数
fmt.Println(compute(add)) // add 是参数
}
23 函数闭包
Go函数可以是一个闭包。
func adder() func(int) int {
sum := 0
//fun 是一个闭包,它引用了函数体之外(本身fn之外)的变量
fn := func(x int) int {
sum += x
return sum
}
return fn
}
func main() {
pos, neg := adder(), adder() //pos.neg是一个闭包,有各自的绑定的sum变量
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
24 在结构类型上定义方法
type Vertex struct {
X, Y float64
}
//方法 Sqrt被 v接收,v出现在 func 关键字和 方法Sqrt名 之间
func (v *Vertex) Sqrt() float64 {
return math.Sqrt(v.X * v.X + v.Y*v.Y)
}
func main() {
p := &Vertex{3, 4}
fmt.Println(p.Sqrt())
}
其实,可以在保内的任何类型定义任意方法,基础类型和其他包的类型除外。
type myfloat float64
//如果只读,使用值作为接收者,函数内部是调用者的副本
func (f myfloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
//如果是可写,使用指针作为接收者
func (f *myfloat) Abs2() float64 {
if *f < 0 {
*f = -*f
return float64(-*f)
}
return float64(*f)
}
func main() {
fmt.Println((myfloat(-5.5)).Abs() )
f := myfloat(-5.5)
(&f).Abs2()
}
25 接口
type myfloat float64
type Iface interface {
Abs() float64
}
func (f myfloat) Abs() float64 {
if f < 0 {
return -float64(f)
}
return float64(f)
}
func main() {
var a Iface
f := myfloat(-5.5)
a = f;
fmt.Println(a.Abs())
}
26 Web服务器 包http 通过实现了http.Handler的接口来响应HTTP请求
type Hello struct{}
func (h Hello) ServeHTTP(
w http.ResponseWriter,
r *http.Request) {
fmt.Fprint(w, "Hello!")
}
func main() {
var h Hello
err := http.ListenAndServe("localhost:4000", h)
if err != nil {
log.Fatal(err)
}
}
27 goroutine
goroute 是由go 运行时环境管理的轻量级线程 。语法:go f(x, y, x)