Go官網html
第一種,本地項目學習 如何使用 go 命令來獲取、構建並安裝包、命令及運行測試java
第二種,在線學習工具使用。 第一部分只是簡單歡迎引導。python
指南的使用linux
歡迎來到Go編程語言指南。本指南涵蓋了該語言的大部分重要特性,主要包括:golang
歡迎!
學習如何使用本指南:包括如何在不一樣的課程之間切換,以及如何運行代碼。
複製代碼
基礎編程
一開始,將學習關於語言的全部基礎內容。segmentfault
定義變量,調用函數,以及在您學習下一課以前所須要瞭解的所有內容。windows
包,變量和函數。
學習Go程序的基本組件。
複製代碼
流程控制語句:for,if,else和switch
學習如何用條件,循環和開關語句控制代碼的流程。
複製代碼
複雜類型:struct,slice和map。
學習如何基於現有類型定義新的類型:本課涵蓋告終構體,分佈,切片和地圖。
複製代碼
方法和接口數組
學習如何爲類型定義方法;如何定義接口;以及如何將全部內容互換起來。bash
方法和接口
本課包含了方法和接口,能夠用它們來定義對象和其行爲。
複製代碼
併發
做爲語言的核心部分,轉到提供了併發的特性。
這一部分概述了goroutein和通道,以及如何使用它們來實現不一樣的併發模式。
併發
Go將併發爲語言的核心構成。本課將進行進行介紹,並提供一些示例來展現如何使用它們。
複製代碼
/*fmt標準庫是咱們在學習Go語言過程當中接觸最先最多使用的庫, #fmt包實現了相似C語言printf和scanf的格式化I/O。主要分爲向外輸出內容和獲取輸入內容兩大部分 */
import (
"fmt"
"math/rand" # math/rand 額外導入的包
)
#
/*fmt向外輸出相關函數 Print系列函數會將內容輸出到系統的標準輸出 */
fmt.Print //Print函數直接輸出內容
fmt.Fprint //Printf函數支持格式化輸出字符串
fmt.Println //Println函數會在輸出內容的結尾添加一個換行符
fmt.Sprint
fmt.Errorf
fmt.Scan
fmt.Scanf
fmt.Scanln
// 這裏比較全:https://www.cnblogs.com/wanghui-garcia/p/10326395.html
複製代碼
用首字母大小寫來區分公開,私有函數?
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
複製代碼
?
var 語句定義了一個變量的列表;跟函數的參數列表同樣,類型在後面。
就像在這個例子中看到的同樣,var
語句能夠定義在包或函數級別。
變量定義能夠包含初始值,每一個變量對應一個。
若是初始化是使用表達式,則能夠省略類型;變量從初始值中得到類型。
在函數中,:=
簡潔賦值語句在明確類型的地方,能夠用於替代 var 定義。
函數外的每一個語句都必須以關鍵字開始(var
、func
、等等),:=
結構不能使用在函數外。
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
複製代碼
Go 的基本類型有Basic types
bool
string
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 的別名
rune // int32 的別名 // 表明一個Unicode碼
float32 float64
complex64 complex128 這個例子演示了具備不一樣類型的變量。 同時與導入語句同樣,變量的定義「打包」在一個語法塊中。
變量在定義時沒有明確的初始化時會賦值爲_零值_。
零值是:
數值類型爲 0
, 布爾類型爲 false
, 字符串爲 ""
(空字符串)。
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s)
}
複製代碼
表達式 T(v) 將值 v 轉換爲類型 T
。
一些關於數值的轉換:
var i int = 42 var f float64 = float64(i) var u uint = uint(f) 或者,更加簡單的形式:
i := 42 f := float64(i) u := uint(f) 與 C 不一樣的是 Go 的在不一樣類型之間的項目賦值時須要顯式轉換。 試着移除例子中 float64 或 int 的轉換看看會發生什麼。
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z int = int(f)
fmt.Println(x, y, z)
}
複製代碼
在定義一個變量但不指定其類型時(使用沒有類型的 var 或 := 語句), 變量的類型由右值推導得出。
當右值定義了類型時,新變量的類型與其相同:
var i int j := i // j 也是一個 int 可是當右邊包含了未指名類型的數字常量時,新的變量就多是 int 、 float64 或 complex128
。 這取決於常量的精度:
i := 42 // int f := 3.142 // float64 g := 0.867 + 0.5i // complex128 嘗試修改演示代碼中 v 的初始值,並觀察這是如何影響其類型的。
func main() {
v := 42 // change me!
fmt.Printf("v is of type %T\n", v)
}
複製代碼
常量的定義與變量相似,只不過使用 const 關鍵字。
常量能夠是字符、字符串、布爾或數字類型的值。
常量不能使用 := 語法定義。
const Pi = 3.14
func main() {
const World = "世界"
fmt.Println("Hello", World)
fmt.Println("Happy", Pi, "Day")
const Truth = true
fmt.Println("Go rules?", Truth)
}
複製代碼
數值常量是高精度的 值。
一個未指定類型的常量由上下文來決定其類型。
也嘗試一下輸出 needInt(Big) 吧。
package main
import "fmt"
const (
Big = 1 << 100
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}
複製代碼
Go 只有一種循環結構——for
循環。
基本的 for 循環除了沒有了 ( )
以外(甚至強制不能使用它們),看起來跟 C 或者 Java 中作的同樣,而 { }
是必須的。
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
複製代碼
跟 C 或者 Java 中同樣,可讓前置、後置語句爲空。
func main() {
sum := 1
for ; sum < 1000; {
sum += sum
}
fmt.Println(sum)
}
複製代碼
基於此能夠省略分號:C 的 while 在 Go 中叫作 for
。
func main() {
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
複製代碼
若是省略了循環條件,循環就不會結束,所以能夠用更簡潔地形式表達死循環。
func main() {
for {
}
}
複製代碼
if 語句除了沒有了 ( )
以外(甚至強制不能使用它們),看起來跟 C 或者 Java 中的同樣,而 { }
是必須的。
(耳熟嗎?)
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
func main() {
fmt.Println(sqrt(2), sqrt(-4))
}
複製代碼
跟 for 同樣,if
語句能夠在條件以前執行一個簡單的語句。
由這個語句定義的變量的做用域僅在 if 範圍以內。
(在最後的 return 語句處使用 v 看看。)
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
複製代碼
在 if 的便捷語句定義的變量一樣能夠在任何對應的 else 塊中使用。
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
} else {
fmt.Printf("%g >= %g\n", v, lim)
}
// 這裏開始就不能使用 v 了
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
複製代碼
func Sqrt(x float64) float64 {
}
func main() {
fmt.Println(Sqrt(2))
}
複製代碼
一個結構體(struct
)就是一個字段的集合。
除非以 fallthrough 語句結束,不然分支會自動終止。
複製代碼
func main() { fmt.Print("Go runs on ") 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 的條件從上到下的執行,當匹配成功的時候中止。
(例如,
switch i {
case 0:
case f():
}
複製代碼
當 i==0 時不會調用 f
。)
注意:Go playground 中的時間老是從 2009-11-10 23:00:00 UTC 開始, 如何校驗這個值做爲一個練習留給讀者完成。
func main() {
fmt.Println("When's Saturday?")
today := time.Now().Weekday()
switch time.Saturday {
case today + 0:
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow.")
case today + 2:
fmt.Println("In two days.")
default:
fmt.Println("Too far away.")
}
}
複製代碼
沒有條件的 switch 同 switch true
同樣。
這一構造使得能夠用更清晰的形式來編寫長的 if-then-else 鏈。
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
複製代碼
defer 語句會延遲函數的執行直到上層函數返回。 延遲調用的參數會馬上生成,可是在上層函數返回前函數都不會被調用。
func main() {
defer fmt.Println("world") // 上層函數也就是main函數了,這和js的defer執行順序很類似
fmt.Println("hello")
}
# 執行結果
hello
world
複製代碼
延遲的函數調用被壓入一個棧中。當函數返回時, 會按照後進先出的順序調用被延遲的函數調用。
閱讀博文了解更多關於 defer 語句的信息。
func main() {
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
}
// 這個settimeout的作法基本相似
複製代碼
爲何要有指針? 指針能夠提升性能,指針能夠節省複製的開銷,但同時要考慮解引用和垃圾回收帶來的影響。 www.jianshu.com/p/7e8ea1b83…
指針的好處:
1.函數的值傳遞,沒法經過調用函數,來修改函數的實參。
2.被調用函數須要提供更多的「返回值」,給調用函數。
3.指針能極大的提升效率(共享內存數據)。 blog.csdn.net/zengzisuzi/…
Go 具備指針。 指針保存了變量的內存地址。
類型 *T 是指向類型 T 的值的指針。其零值是 `nil`。
var p *int
& 符號會生成一個指向其做用對象的指針。
i := 42
p = &i
* 符號表示指針指向的底層的值。
fmt.Println(*p) // 經過指針 p 讀取 i
*p = 21 // 經過指針 p 設置 i
這也就是一般所說的「間接引用」或「非直接引用」。
複製代碼
與 C 不一樣,Go 沒有指針運算。「Go語言裏面的指針和C++指針同樣,都是指向某塊內存的地址值,能夠解引用,不一樣只是在於C++裏能夠直接對指針作算術運算而Go裏面不行。」
而 C#、java這些高級語言是沒有指針的。
一個結構體(struct
)就是一個字段的集合。 (而 type 的含義跟其字面意思相符。)
結構體和類很是類似。
Go裏面它確實沒有類,要表示對象,它是用struct的(和C很像);Go語言,是一門沒有對象的OOP。
Go的面向對象 blog.csdn.net/u011606307/…
使用 Name: 語法能夠僅列出部分字段。(字段名的順序無關。) 特殊的前綴 & 返回一個指向結構體的指針。
類型 [n]T 是一個有 n 個類型爲 T 的值的數組。
表達式 var a [10]int 定義變量 a 是一個有十個整數的數組。
數組的長度是其類型的一部分,所以數組不能改變大小。 這看起來是一個制約,可是請不要擔憂; Go 提供了更加便利的方式來使用數組。
一個 slice 會指向一個序列的值,而且包含了長度信息。
[]T 是一個元素類型爲 T 的 slice。
slice 能夠從新切片,建立一個新的 slice 值指向相同的數組。
表達式
s[lo:hi] 表示從 lo 到 hi-1 的 slice 元素,含兩端。所以
s[lo:lo] 是空的,而
s[lo:lo+1] 有一個元素。
slice 由函數 make 建立。這會分配一個零長度的數組而且返回一個 slice 指向這個數組:
a := make([]int, 5) // len(a)=5 爲了指定容量,可傳遞第三個參數到 make
:
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
b = b[:cap(b)] // len(b)=5, cap(b)=5 b = b[1:] // len(b)=4, cap(b)=4
slice 的零值是 nil
。
一個 nil 的 slice 的長度和容量是 0。
向 slice 添加元素是一種常見的操做,所以 Go 提供了一個內建函數 append
。 內建函數的文檔對 append 有詳細介紹。
func append(s []T, vs ...T) []T append 的第一個參數 s 是一個類型爲 T 的數組,其他類型爲 T 的值將會添加到 slice。
append 的結果是一個包含原 slice 全部元素加上新添加的元素的 slice。
若是 s 的底層數組過小,而不能容納全部值時,會分配一個更大的數組。 返回的 slice 會指向這個新分配的數組。
(瞭解更多關於 slice 的內容,參閱文章slice:使用和內幕。)
for 循環的 range 格式能夠對 slice 或者 map 進行迭代循環 range(續) 能夠經過賦值給 _ 來忽略序號和值。
若是隻須要索引值,去掉「, value」的部分便可。
練習:slice 實現 Pic
。它返回一個 slice 的長度 dy
,和 slice 中每一個元素的長度的 8 位無符號整數 dx
。當執行這個程序,它會將整數轉換爲灰度(好吧,藍度)圖片進行展現。
圖片的實現已經完成。可能用到的函數包括 (x+y)/2 、 x*y 和 x^y
(使用 math.Pow 計算最後的函數)。
(須要使用循環來分配 [][]uint8 中的每一個 []uint8
。)
(使用 uint8(intValue) 在類型之間進行轉換。)
map 映射鍵到值。
map 在使用以前必須用 make 而不是 new 來建立;
map 的文法 map 的文法跟結構體文法類似,不過必須有鍵名。
map 的文法(續) 若是頂級的類型只有類型名的話,能夠在文法的元素中省略鍵名。
修改 map 在 map m 中插入或修改一個元素:
m[key] = elem 得到元素:
elem = m[key] 刪除元素:
delete(m, key) 經過雙賦值檢測某個鍵存在:
elem, ok = m[key] 若是 key 在 m 中,ok
爲 true 。不然, ok 爲 false
,而且 elem 是 map 的元素類型的零值。
一樣的,當從 map 中讀取某個不存在的鍵時,結果是 map 的元素類型的零值。
練習:map 實現 WordCount
。它應當返回一個含有 s 中每一個 「詞」 個數的 map。函數 wc.Test 針對這個函數執行一個測試用例,並輸出成功仍是失敗。
你會發現 strings.Fields 頗有幫助。
函數也是值。
Go 函數能夠是閉包的。閉包是一個函數值,它來自函數體的外部的變量引用。 函數能夠對這個引用值進行訪問和賦值;換句話說這個函數被「綁定」在這個變量上。
例如,函數 adder 返回一個閉包。每一個閉包都被綁定到其各自的 sum 變量上。
練習:斐波納契閉包 如今來經過函數作些有趣的事情。
實現一個 fibonacci 函數,返回一個函數(一個閉包)能夠返回連續的斐波納契數。