main 包中的main函數是程序的入口;java
1 逐個導入python
import "fmt"
import "math"
複製代碼
2 分組導入linux
import (
"fmt"
"math"
)
複製代碼
官方建議使用分組導入的方式數組
在 Go 中,若是一個名字以大寫字母開頭,那麼它就是已導出的;在導入一個包時,你只能引用其中已導出的名字。任何「未導出」的名字在該包外均沒法訪問。閉包
例如math 包中的Pi是導出的,pi是未導出的,執行程序時math.pi會報錯,而math.Pi能夠正常運行函數
函數能夠沒有參數或接受多個參數;ui
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
複製代碼
注意:當連續兩個或多個函數的已命名形參類型相同時,除最後一個類型之外,其它均可以省略。spa
func add(x, y int) int {
return x + y
}
複製代碼
上面的函數中線程
x int, y int
複製代碼
被縮寫爲指針
x, y int
複製代碼
函數能夠返回任意數量的返回值。
func swap(x, y string) (string, string) {
return y, x
}
複製代碼
var 語句用於聲明一個變量或一個變量列表。
var c bool
var python, java bool
複製代碼
只在函數內有效的變量相似於Java中的局部變量,使用:= 符號聲明。
func main() {
k := 3
}
複製代碼
注意::= 結構不能在函數外使用。
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 類型,除非你有特殊的理由使用固定大小或無符號的整數類型
能夠使表達式 T(v) 將值 v 轉換爲類型 T。例如:
var i int = 42
var f float64 = float64(i)
複製代碼
注意:Go 在不一樣類型的項之間賦值時必需要顯式轉換。
常量的聲明與變量相似,使用 const 關鍵字。
常量能夠是字符、字符串、布爾值或數值。
常量不能用 := 語法聲明。
const Pi = 3.14
複製代碼
Go 只有一種循環結構:for 循環
for i := 0; i < 10; i++ {
sum += i
}
複製代碼
i := 0 初始化語句 i < 10 條件表達式 i++ 後置語句
和Java很是像了。
初始化語句和後置語句也是可選的
for ; sum < 1000; {
sum += sum
}
複製代碼
for {
}
複製代碼
if 語句與 for 循環相似,表達式外無需小括號 ( ) ,而大括號 { } 則是必須的。
if x < 0 {
return sqrt(-x) + "i"
}
複製代碼
if 語句能夠在條件表達式前執行一個簡單的語句,該語句聲明的變量做用域僅在 if 以內。
if v := math.Pow(x, n); v < lim {
return v
}
複製代碼
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
fmt.Printf("%s.\n", os)
}
複製代碼
case 無需爲常量,且取值沒必要爲整數。
沒有條件的 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")
fmt.Println("hello")
}
複製代碼
結果爲:
hello
world
複製代碼
原理:推遲的函數調用會被壓入一個棧中。當外層函數返回時,被推遲的函數會按照後進先出的順序調用。
Go 擁有指針。指針保存了值的內存地址。類型 *T 是指向 T 類型值的指針。其零值爲 nil。
var p *int
& 操做符會生成一個指向其操做數的指針。
i := 42
p = &i
星號操做符表示指針指向的底層值。
fmt.Println(*p) // 經過指針 p 讀取 i 結果爲42
*p = 21 // 經過指針 p 設置 i
fmt.Println(*p) //結果爲21
相似於Java中的實體,一個結構體(struct)就是一組字段(field)。
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
複製代碼
注意:結構體中的字段也能夠經過指針來訪問。
表達式:[n]T 表示擁有 n 個 T 類型的值的數組。
var a [10]int
複製代碼
注意:數組的長度是其類型的一部分,所以數組不能改變大小。
切片爲數組元素提供動態大小的、靈活的視角,在實踐中,切片比數組更經常使用。
類型 []T 表示一個元素類型爲 T 的切片。
切片經過兩個下標來界定,即一個上界和一個下界,兩者以冒號分隔:
a[low : high]
它會選擇一個半開區間,包括第一個元素,但排除最後一個元素。
如下表達式建立了一個切片,它包含 a 中下標從 1 到 3 的元素:
a[1:4]
切片並不存儲任何數據,它只是描述了底層數組中的一段。
更改切片的元素會修改其底層數組中對應的元素。
與它共享底層數組的切片都會觀測到這些修改。
對於數組
var a [10]int 來講,如下切片是等價的:
a[0:10]
a[:10]
a[0:]
a[:]
複製代碼
切片的長度就是它所包含的元素個數,能夠經過len(s)獲取 切片的容量是從它的第一個元素開始數,到其底層數組元素末尾的個數,能夠經過cap(s)獲取。
切片的零值是 nil。
nil 切片的長度和容量爲 0 且沒有底層數組。
切片能夠用內建函數 make 來建立,這也是建立動態數組的方式。
切片中能夠包含其餘切片。
Go 沒有類。不過你能夠爲結構體類型定義方法。
方法就是一類帶特殊的 接收者 參數的函數。
方法接收者在它本身的參數列表內,位於 func 關鍵字和方法名之間。
在此例中,Abs 方法擁有一個名爲 v,類型爲 Vertex 的接收者。
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
複製代碼
注意:方法只是個帶接收者參數的函數。
非結構體也可定義方法,例如:
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
複製代碼
接口類型 是由一組方法簽名定義的集合,接口類型的變量能夠保存任何實現了這些方法的值。
Go 程(goroutine)是由 Go 運行時管理的輕量級線程。
go f(x, y, z)會啓動一個新的 Go 程並執行
f(x, y, z)f, x, y 和 z 的求值發生在當前的 Go 程中,而 f 的執行發生在新的 Go 程中。
Go 程在相同的地址空間中運行,所以在訪問共享的內存時必須進行同步。
信道是帶有類型的管道,適合在各個 Go 程間進行通訊。你能夠經過它用信道操做符 <- 來發送或者接收值。
ch <- v // 將 v 發送至信道 ch。
v := <-ch // 從 ch 接收值並賦予 v。(「箭頭」就是數據流的方向。)
複製代碼
和映射與切片同樣,信道在使用前必須建立:
ch := make(chan int)
複製代碼
默認狀況下,發送和接收操做在另外一端準備好以前都會阻塞。這使得 Go 程能夠在沒有顯式的鎖或競態變量的狀況下進行同步。
信道能夠是 帶緩衝的。將緩衝長度做爲第二個參數提供給 make 來初始化一個帶緩衝的信道:
ch := make(chan int, 100)
複製代碼
僅當信道的緩衝區填滿後,向其發送數據時纔會阻塞。當緩衝區爲空時,接受方會阻塞。