這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
一、安裝
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 mainimport "fmt"func main() { fmt.Printf("hello, world\n")}
使用go tool 編譯該項目
# go install hello# $GOPATH/bin/hellohello, world
二、go 文法學習
基本類型
boolstringint int8 int16 int32 int64uint uint8 uint16 uint32 uint64 uintptrbyte // uint8 的別名rune // int32 的別名 // 代表一個Unicode碼float32 float64complex64 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 mainimport "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 boolvar (ToBe bool = falseMaxInt uint64 = 1<<64 - 1z 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 為 ""(Null 字元串)
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 := 1for ; sum < 1000; { sum += sum}
11 for 是go 的while
sum := 1for 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")}
#./teststartdone9876543210
16、指標
go沒有指標運行符
x, y := 12,13p := &xfmt.Println(*p) #即將列印12p = &y*p = 21fmt.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]stringa[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]) }
結果
#./testhello0 world0hello1 world1hello2 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)}}
輸出
# ./test2**0 = 12**1 = 22**2 = 42**3 = 82**4 = 162**5 = 322**6 = 642**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]intfunc 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 += xreturn 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 float64type 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 Helloerr := http.ListenAndServe("localhost:4000", h)if err != nil {log.Fatal(err)}}
27 goroutine
goroute 是由go 運行時環境管理的輕量級線程 。文法:go f(x, y, x)