1.go語言反對函數和操做符的重載
2.go語言支持類、類成員方法、類的組合,反對繼承,反對虛函數和虛函數重載;不過go語言也提供了重載,採用的是組合的文件提供。
3.go語言放棄了構造函數和析構函數
4.go語言提供接口【interface】 ,非入侵性
5.go語言主要特性:
自動垃圾回收
更豐富的內置類型
函數多返回值
錯誤處理
匿名函數和閉包
類型和接口
併發編程
反射
語言交互性
6.go語言可多返回值功能,對於不感興趣的返回值可使用下劃線避免;
7.錯誤處理:go語言的錯誤處理機制能夠大量減小代碼量
3個關鍵詞:defer、panic、recover html
1.每一個go源代碼文件的開頭都是一個package申明,表示該go所屬的包,包是go語言裏最基本的分發單位,也是工程管理中依賴關係的體現,執行go語言需創建一個main的包
2.main函數不能帶參數,也不能定義返回值,命令行傳入的參數在os.Args變量中保存,如需支持命令行開關,需使用flag包
3.不得包含代碼文件中沒有用到的包,不然go編譯器會報錯
4.函數以關鍵字func 開頭
func 函數名(參數列表)(返回值列表){
//函數體
}
5.go代碼中不要求開發者在每一個語句後面加上分號表示語句結束
6.查看go編譯器是否安裝
go version
7.程序編譯和運行
go run 文件名 #編譯+連接+運行 3個步驟合併爲一步
8.只編譯
go build 文件名
./文件名
9.變量:go語言中的變量使用方式與C語言接近,但具有更大的靈活性
10.變量申明
1).關鍵字var
2).類型放在變量名以後
3).變量申明不須要使用分號做爲結束符
var v1 int
var v2 string
var v3 [10]int //數組
var v4 []int //數組切片
var v5 struct {
f int
}
var v6 *int //指針
var v7 map[string]int
var v8 func(a int) int linux
11.變量初始化 var關鍵字能夠保留,但不是必要的元素
var v1 int = 10
var v2 = 10
v3 := 10
出如今:=左側的變量不該該是已經申明過的
12.go語言中變量初始化和賦值是兩個不一樣的概念
13.變量交換語句
i, j = j, i
14.匿名變量
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
//若只須要得到nickName,能夠這樣寫
_, _, nickName := GetName()
15.常量 :能夠是:整形、浮點型、複數類型、布爾類型、字符串類型
16.常量定義
1).關鍵字const
2).若是定義常量時沒有指定類型,那麼他與字面常量同樣,是無類型常量
17.因爲常量的賦值是一個編譯期行爲,因此右值不能出現任何須要運行期才能得出結果的表達式,好比試圖以以下方式定義常量就會致使編譯錯誤:
const Home = os.GetEnv("HOME")
18.Go語言預約義了這些常量: true、 false和iota,iota比較特殊,能夠被認爲是一個可被編譯器修改的常量,在每個const關鍵字出現時被重置爲0,而後在下一個const出現以前,每出現一次iota,其所表明的數字會自動增1
const ( // iota被重設爲0
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
19.枚舉
const (
Sunday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 這個常量沒有導出
)
同Go語言的其餘符號( symbol)同樣,以大寫字母開頭的常量在包外可見
20.類型
布爾類型: bool。
整型: int八、 byte、 int1六、 int、 uint、 uintptr等。
浮點類型: float3二、 float64。
複數類型: complex6四、 complex128。
字符串: string。
字符類型: rune。
錯誤類型: error。
此外, Go語言也支持如下這些複合類型:
指針( pointer)
數組( array)
切片( slice)
字典( map)
通道( chan)
結構體( struct)
接口( interface)
21.布爾類型:布爾不接受其餘類型的賦值,不支持自動或強制類型轉換
22.整型:int和int32在go語言中被認爲是兩種不一樣的類型,編譯器也不會幫你自動作類型轉換
23.不一樣類型的整型數不能直接進行比較,但各類類型的整型變量能夠和字面常量進行比較
24.運算符:go語言基本同C語言,除了取反
go語言中:取反^x
25.浮點型:表示包含小數點的數據,採用IEEE-754標準的表達式
go語言中定義了兩個類型float32和float64,其中float32表示C語言中的float型,float64表示C語言中的double類型
26.複數類型:實部(real),虛部(imag)
var value1 complex64
value1 = 3.2 + 12i
27.字符串:
1).字符串操做
x+y 字符串鏈接
len(s) len("hello") //結果爲5
s[i] 取字符 "hello"[1] //結果爲e
中文字符UTF-8佔3個字節
28.字符類型:一個是byte ,表明UTF-8字符串的單個字節的值,
rune,表明Unicode字符
29.數組:在go語言中,數組長度在定之後就不可更改
元素訪問:可使用數組下標來訪問數組中的元素
關鍵字range 用於便捷地遍歷容器中的元素,數組也是range的支持範圍
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
range具備兩個返回值,第一個返回值是元素的數組下標,第二個返回值是元素的值
須要特別注意的是,在Go語言中數組是一個值類型( value type)。全部的值類型變量在賦值和做爲參數傳遞時都將產生一次複製動做。若是將數組做爲函數的參數類型,則在函數調用時該參數將發生數據複製。所以,在函數體中沒法修改傳入的數組的內容,由於函數內操做的只是所傳入數組的一個副本。
30.數組切片:git
Go語言提供了數組切片( slice)這個很是酷的功能來彌補數組的不足數組切片就像一個指向數組的指針,實際上它擁有本身的數據結構,而不只僅是個指針。數組切片的數據結構能夠抽象爲如下3個變量:
1).一個指向原生數組的指針
2).數組切片中的元素個數
3).數組切片已分配的內存空間
建立數組切片的方法主要有兩種——基於數組和直接建立
基於數組:
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 基於數組建立一個數組切片
var mySlice []int = myArray[:5]
Go語言支持用myArray[first:last]這樣的方式來基於數組生成一
個數組切片,並且這個用法還很靈活,
基於myArray的全部元素建立數組切片:
mySlice = myArray[:]
基於myArray的前5個元素建立數組切片:
mySlice = myArray[:5]
直接建立: Go語言提供的內置函數make()能夠用於靈活地建立數組切片
建立一個初始元素個數爲5的數組切片,元素初始值爲0:
mySlice1 := make([]int, 5)
建立一個初始元素個數爲5的數組切片,元素初始值爲0,並預留10個元素的存儲空間:
mySlice2 := make([]int, 5, 10)
直接建立並初始化包含5個元素的數組切片:
mySlice3 := []int{1, 2, 3, 4, 5}
數組切片支持Go語言內置的cap()函數和len()函數,cap()函數返回的是數組切片分配的空間大小,而len()函數返回的是
數組切片中當前所存儲的元素個數;append()函數能夠往尾端加入新的元素
mySlice := make([]int, 5, 10)
mySlice = append(mySlice, 1, 2, 3)
函數append()的第二個參數實際上是一個不定參數,咱們能夠按本身需求添加若干個元素
甚至直接將一個數組切片追加到另外一個數組切片的末尾
mySlice2 := []int{8, 9, 10}
// 給mySlice後面添加另外一個數組切片
mySlice = append(mySlice, mySlice2...)
在第二個參數mySlice2後面加了三個點,即一個省略號,若是沒有這個省略號的話,會有編譯錯誤
數組切片會自動處理存儲空間不足的問題。若是追加的內容長度超過當前已分配的存儲空間
(即cap()調用返回的信息),數組切片會自動分配一塊足夠大的內存
基於數組切片建立數組切片
oldSlice := []int{1, 2, 3, 4, 5}
newSlice := oldSlice[:3] // 基於oldSlice的前3個元素構建新數組切片
內容複製
數組切片支持Go語言的另外一個內置函數copy(),用於將內容從一個數組切片複製到另外一個數組切片。若是加入的兩個數組切片不同大,就會按其中較小的那個數組切片的元素個數進行復制、
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只會複製slice1的前3個元素到slice2中
copy(slice1, slice2) // 只會複製slice2的3個元素到slice1的前3個位置
31.map
map是一堆鍵值對的未排序集合
1).變量申明:map的申明基本沒有多餘的元素
var myMap map[string] PersonInfo
myMap是聲明的map變量名, string是鍵的類型, PersonInfo則是其中所存放的值類型
2).建立
建立了一個鍵類型爲string、值類型爲PersonInfo的map:
myMap = make(map[string] PersonInfo)
也能夠選擇是否在建立時指定該map的初始存儲能力,下面的例子建立了一個初始存儲能力爲100的map:
myMap = make(map[string] PersonInfo, 100)
3).元素賦值 將鍵和值用下面的方式對應起來便可
myMap["1234"] = PersonInfo{"1", "Jack", "Room 101,..."}
4).元素刪除
Go語言提供了一個內置函數delete(),用於刪除容器內的元素
delete(myMap, "1234")
5).元素查找
<1>. 聲明並初始化一個變量爲空
<2>. 試圖從map中獲取相應鍵的值到該變量中
<3>. 判斷該變量是否依舊爲空,若是爲空則表示map中沒有包含該變量
32.控制流程
選擇、循環、跳轉
條件語句 if、 else和else if
選擇語句 switch、 case和select
循環語句 for和range
跳轉語句 goto
1).條件語句:
<1>. 條件語句不須要使用括號將條件包含起來();
<2>. 不管語句體內有幾條語句,花括號{}都必須存在;
<3>. 左花括號{必須與if或者else處於同一行;
<4>. 在if以後,條件語句以前,能夠添加變量初始化語句,使用;間隔;
<5>. 在有返回值的函數中,不容許將「最終的」 return語句包含在if...else...結構中,不然會編譯失敗
編譯失敗的案例以下:
func example(x int) int {
if x == 0 {
return 5
} else {
return x
}
}
2).選擇語句
<1>. 左花括號{必須與switch處於同一行;
<2>. 條件表達式不限制爲常量或者整數;
<3>. 單個case中,能夠出現多個結果選項;
<4>. 與C語言等規則相反, Go語言不須要用break來明確退出一個case;
<5>. 只有在case中明確添加fallthrough關鍵字,纔會繼續執行緊跟的下一個case;
<6>. 能夠不設定switch以後的條件表達式,在此種狀況下,整個switch結構與多個
if...else...的邏輯做用等同
switch i {
case 0:
fmt.Printf("0")
case 1:
fmt.Printf("1")
case 2:
fallthrough
case 3:
fmt.Printf("3")
case 4, 5, 6:
fmt.Printf("4, 5, 6")
default:
fmt.Printf("Default")
}
switch後面的表達式甚至不是必需的,好比下面的例子:
switch {
case 0 <= Num && Num <= 3:
fmt.Printf("0-3")
case 4 <= Num && Num <= 6:
fmt.Printf("4-6")
case 7 <= Num && Num <= 9:
mt.Printf("7-9")
}
3).循環語句 Go語言中的循環語句只支持for關鍵字,而不支持while和do-while結構
<1>. 左花括號{必須與for處於同一行
<2>. Go語言中的for循環與C語言同樣,都容許在循環條件中定義和初始化變量,惟一的區別是,Go語言不支持以逗號爲間隔的多個賦值語句,必須使用平行賦值的方式來初始化多個變量
<3>. Go語言的for循環一樣支持continue和break來控制循環,可是它提供了一個更高級的break,能夠選擇中斷哪個循環
for後面的條件表達式不須要用圓括號()包含起來
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
Go語言無限循環的場景
sum := 0
for {
sum++
if sum > 100 {
break
}
}
a := []int{1, 2, 3, 4, 5, 6}
for i, j := 0, len(a) – 1; i < j; i, j = i + 1, j – 1 {
a[i], a[j] = a[j], a[i]
}
4).跳轉語句
goto語句的語義很是簡單,就是跳轉到本函數內的某個標籤
func myfunc() {
i := 0
HERE:
fmt.Println(i)
i++
if i < 10 {
goto HERE
}
}
33.函數 基本組成:關鍵字func、函數名、參數列表、返回值、函數體和返回值語句
若是參數列表中若干個相鄰的參數類型的相同,則能夠在參數列表中省略前面變量的類型聲明
func Add(a, b int)(ret int, err error) {
// ...
}
34.函數調用
注意:小寫字母開頭的函數只在本包內可見,大寫字母開頭的函數才能被其餘包使用。
這個規則也適用於類型和變量的可見性。
35.不定參數
1).不定參數類型
不定參數是指函數傳入的參數個數爲不定數量
func myfunc(args ...int) {
for _, arg := range args {
fmt.Println(arg)
}
}
函數myfunc()接受不定數量的參數,這些參數的類型所有是int
形如...type格式的類型只能做爲函數的參數類型存在,而且必須是最後一個參數。它是一
個語法糖( syntactic sugar),即這種語法對語言的功能並無影響,可是更方便程序員使用。通
常來講,使用語法糖可以增長程序的可讀性,從而減小程序出錯的機會
2).不定參數的傳遞
func myfunc(args ...int) {
// 按原樣傳遞
myfunc3(args...)
// 傳遞片斷,實際上任意的int slice均可以傳進去
myfunc3(args[1:]...)
}
3).任意類型的不定參數
能夠指定類型爲interface{}
func Printf(format string, args ...interface{}) {
// ...
}
36.多返回值
37.匿名函數
匿名函數由一個不帶函數名的函數聲明和函數體組成
func(a, b int, z float64) bool {
return a*b <int(z)
}
匿名函數能夠直接賦值給一個變量或者直接執行
f := func(x, y int) int {
return x + y
}
func(ch chan int) {
ch <- ACK
} (reply_chan) // 花括號後直接跟參數列表表示函數調用
閉包:閉包是能夠包含自由(未綁定到特定對象)變量的代碼塊,這些變量不在這個代碼塊內或者
任何全局上下文中定義,而是在定義代碼塊的環境中定義。要執行的代碼塊(因爲自由變量包含
在代碼塊中,因此這些自由變量以及它們引用的對象沒有被釋放)爲自由變量提供綁定的計算環境(做用域)
38.錯誤處理
1).error接口
type error interface {
Error() string
}
2).defer
若是以爲一句話幹不完清理的工做,也可使用在defer後加一個匿名函數的作法:
defer func() {
// 作你複雜的清理工做
} ()
defer語句的調用是遵守 :先進後出的原則
3).panic() 和recover()
Go語言引入了兩個內置函數panic()和recover()以報告和處理運行時錯誤和程序中的錯誤場景
func panic(interface{})
func recover() interface{}
recover()函數用於終止錯誤處理流程
defer func() {
if r := recover(); r != nil {
log.Printf("Runtime error caught: %v", r)
}
}()
foo()程序員
1.爲類型添加方法
能夠給任意類型(包括內置類型,但不包括指針類型)添加相應的方法
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
/**************************************************/
func (a Integer) Less(b Integer) bool { // 面向對象
return a < b
}
func Integer_Less(a Integer, b Integer) bool { // 面向過程
return a < b
}
a.Less(2) // 面向對象的用法
Integer_Less(a, 2) // 面向過程的用法
面向對象
func (a *Integer) Add(b Integer) {
*a += b
}
這裏爲Integer類型增長了Add()方法。因爲Add()方法須要修改對象的值,因此須要用指
針引用。調用以下:
func main() {
var a Integer = 1
a.Add(2)
fmt.Println("a =", a)
}
2.值語義和引用語義
b = a
b.Modify()
若是b的修改不會影響a的值,那麼此類型屬於值類型。若是會影響a的值,那麼此類型是引用類型
3.結構體
定義:
type Rect struct {
x, y float64
width, height float64
}
初始化:4種方法都行
rect1 := new(Rect)
rect2 := &Rect{}
rect3 := &Rect{0, 0, 100, 200}
rect4 := &Rect{width: 100, height: 200}
未進行顯式初始化的變量都會被初始化爲該類型的零值
類實例化時指針或者實例區別:
注:
實例化類的時候,通常有2個方法:
(1) 用new(structName):這個方法獲得的是*structName類型,即類的指針類型;
var t_t tmpInterface=new(tmpStruct)
(2) 用structName{init para}:這個方法獲得的是structName類型,即類的實例類型,不是指針。
var t_ptr tmpInterface=tmpStruct{}
4.匿名組合
5.可見性
Go語言對關鍵字的增長很是吝嗇,其中沒有private、 protected、 public這樣的關鍵
字。要使某個符號對其餘包( package)可見(便可以訪問),須要將該符號定義爲以大寫字母開頭
6.接口 非侵入式接口
定義:type name interface {
method1(param_list)return_list
method2(param_list)return_list
...
}
7.接口賦值
將對象實例賦值給接口
將接口賦值給另外一個接口
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) {
*a += b
}
type LessAdder interface {
Less(b Integer) bool
Add(b Integer)
}
var a Integer = 1
var b LessAdder = &a
8.Any類型
var v1 interface{} = 1 // 將int類型賦值給interface{}
var v2 interface{} = "abc" // 將string類型賦值給interface{}
var v3 interface{} = &v2 // 將*interface{}類型賦值給interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}github
1.多進程
簡單、進程間互不影響,但系統開銷大,由於全部的進程都是由內核管理的。
2.多線程
開銷小不少,可是其開銷依舊比較大,且在高併發模式下,效率會有影響。
3.基於回調的非阻塞/異步IO
經過事件驅動的方式使用異步IO,使服務器持續運轉,且儘量地少用線程,降
低開銷,它目前在Node.js中獲得了很好的實踐。可是使用這種模式,編程比多線程要復
雜,由於它把流程作了分割,對於問題自己的反應不夠天然
4.協程(coroutine)
系統開銷極小,能夠有效提升線程的任務併發性,而避免多線程的缺點。
使用協程的優勢是編程簡單,結構清晰;缺點是須要語言的支持,
若是不支持,則須要用戶在程序中自行實現調度器。目前,原生支持協程的語言還不多。
5.goroutine :輕量級線程
關鍵字 go
常見的通訊模型 共享數據和消息
6.channel:
消息機制:每一個併發單元是自包含的、獨立的個體,而且都有本身的變量,但在不一樣併發
單元間這些變量不共享。每一個併發單元的輸入和輸出只有一種,那就是消息
channel是類型相關的,一個channel只能傳遞一種類型的值,這個類型須要在聲明channel時指定。
申明:
var chanName chan ElementType //ElementType指定這個channel所能傳遞的元素類型
例:var ch chan int
定義channel,直接使用內置函數make()
ch :=make(chan int) //申明並初始化一個int型的名爲ch的channel
數據寫入channel 向channel寫入數據一般會致使阻塞,直到goroutine從這個channel中讀取數據
ch <- value
從channel中讀取數據
value := <-ch
注:若是channel中沒有數據,從channel中讀取數據也會致使程序阻塞,直到channel寫入數據爲止
7.select 處理異步IO
結構:
select {
case <-chan1:
// 若是chan1成功讀到數據,則進行該case處理語句
case chan2 <- 1:
// 若是成功向chan2寫入數據,則進行該case處理語句 ,寫入1
default:
// 若是上面都沒有成功,則進入default處理流程
}
8.緩存機制
建立一個帶緩衝的channel
c := make(chan int, 1024) //建立一個大小爲1024的int類型channel,能夠一直寫入數據,直到緩衝區寫滿阻塞
從channel中讀取數據,同費緩衝區channel讀取方式一致,可使用range
for i := range c {
fmt.Println("Received:", i)
}
9.超時機制
實現並執行一個匿名的超時等待函數
timeout := make(chan bool, 1)
go func() {
time.Sleep(1e9) // 等待1秒鐘
timeout <- true
}()
// 而後咱們把timeout這個channel利用起來
select {
case <-ch:
// 從ch中讀取到數據
case <-timeout:
// 一直沒有從ch中讀取到數據,但從timeout中讀取到了數據
}
10.單向channel
var ch1 chan int // ch1是一個正常的channel,不是單向的
var ch2 chan<- float64// ch2是單向channel,只用於寫float64數據
var ch3 <-chan int // ch3是單向channel,只用於讀取int數據
channel是一個原生類型,支持被傳遞,支持類型轉換
例:
func Parse(ch <-chan int) {
for value := range ch {
fmt.Println("Parsing value", value)
}
}
11.關閉channel 內置函數close()
close(ch)
判斷一個channel是否已經被關閉,能夠在讀取的時候使用多重返回值的方式:
x, ok := <-ch
返回值是false則表示ch已經被關閉
12.讓出時間片
使用runtime包中Gosched()函數實現
13.同步鎖
Go語言包中的sync包提供了兩種鎖類型: sync.Mutex和sync.RWMutex。 Mutex是最簡單
的一種鎖類型,同時也比較暴力,當一個goroutine得到了Mutex後,其餘goroutine就只能乖乖等
到這個goroutine釋放該Mutex。
var l sync.Mutex
func foo() {
l.Lock()
defer l.Unlock()
//...
}算法
1.Dial()函數
func Dial(net, addr string) (Conn, error)
net參數是網絡協議的名字, addr參數是IP地址或域名,而端口號以「:」的形式跟隨在地址
或域名的後面,端口號可選。若是鏈接成功,返回鏈接對象,不然返回error
TCP連接:
conn, err := net.Dial("tcp", "192.168.0.10:2100")
UDP連接:
conn, err := net.Dial("udp", "192.168.0.12:975")
ICMP連接(使用協議名稱):
conn, err := net.Dial("ip4:icmp", "www.baidu.com")
ICMP連接(使用協議編號):
conn, err := net.Dial("ip4:1", "10.0.0.3")
Dial()函數是對DialTCP()、 DialUDP()、 DialIP()和DialUnix()的封裝,直接調用這些函數,它們的功能是一致的
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error)
func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error)
func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error)
func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error)
net.ResolveTCPAddr(),用於解析地址和端口號;
net.DialTCP(),用於創建連接。
驗證IP地址有效性的代碼以下:
func net.ParseIP()
建立子網掩碼的代碼以下:
func IPv4Mask(a, b, c, d byte) IPMask
獲取默認子網掩碼的代碼以下:
func (ip IP) DefaultMask() IPMask
根據域名查找IP的代碼以下:
func ResolveIPAddr(net, addr string) (*IPAddr, error)
func LookupHost(name string) (cname string, addrs []string, err error)
2.HTTP編程
HTTP( HyperText Transfer Protocol,超文本傳輸協議)是互聯網上應用最爲普遍的一種網絡協議,
定義了客戶端和服務端之間請求與響應的傳輸標準。
HTTP客戶端
基本方法:
func (c *Client) Get(url string) (r *Response, err error)
func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response, err
error)
func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
func (c *Client) Head(url string) (r *Response, err error)
func (c *Client) Do(req *Request) (resp *Response, err error)
<1>.http.Get() 請求一個源
resp, err := http.Get("http://example.com/")
if err != nil {
// 處理錯誤 ...
return
}
defer resp.Body.close()
io.Copy(os.Stdout, resp.Body)
上面這段代碼請求一個網站首頁,並將其網頁內容打印到標準輸出流中。
<2>.http.Post()
要以POST的方式發送數據,只需調用http.Post()方法並依次傳遞下面的3個
參數便可:
請求的目標 URL
將要 POST 數據的資源類型( MIMEType)
數據的比特流( []byte形式)
resp, err := http.Post("http://example.com/upload", "image/jpeg", &imageDataBuf)
if err != nil {
// 處理錯誤
return
}
if resp.StatusCode != http.StatusOK {
// 處理錯誤
return
}
// ...
<3>.http.PostForm()
http.PostForm()方法實現了標準編碼格式爲application/x-www-form-urlencoded的表單提交
resp, err := http.PostForm("http://example.com/posts", url.Values{"title":
{"article title"}, "content": {"article body"}})
if err != nil {
// 處理錯誤
return
}
// ...
<4>.http.Head()
HTTP 中的 Head 請求方式代表只請求目標 URL 的頭部信息,即 HTTP Header 而不返回 HTTP Body
下面的示例代碼請求一個網站首頁的 HTTP Header信息:
resp, err := http.Head("http://example.com/")
<5>.(*http.Client).Do()
在多數狀況下, http.Get()和http.PostForm() 就能夠知足需求,可是若是咱們發起的
HTTP 請求須要更多的定製信息,咱們但願設定一些自定義的 Http Header 字段,好比:
設定自定義的"User-Agent",而不是默認的 "Go http package"
傳遞 Cookie
此時可使用net/http包http.Client對象的Do()方法來實現:
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("User-Agent", "Gobook Custom User-Agent")
// ...
client := &http.Client{ //... }
resp, err := client.Do(req)
// ...
高級封裝
自定義http.Client
type Client struct {
// Transport用於肯定HTTP請求的建立機制。
// 若是爲空,將會使用DefaultTransport
Transport RoundTripper
// CheckRedirect定義重定向策略。
// 若是CheckRedirect不爲空,客戶端將在跟蹤HTTP重定向前調用該函數。
// 兩個參數req和via分別爲即將發起的請求和已經發起的全部請求,最先的
// 已發起請求在最前面。
// 若是CheckRedirect返回錯誤,客戶端將直接返回錯誤,不會再發起該請求。
// 若是CheckRedirect爲空, Client將採用一種確認策略,將在10個連續
// 請求後終止
CheckRedirect func(req *Request, via []*Request) error
// 若是Jar爲空, Cookie將不會在請求中發送,並會
// 在響應中被忽略
Jar CookieJar
}
在Go語言標準庫中, http.Client類型包含了3個公開數據成員:
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
其中Transport類型必須實現http.RoundTripper接口。 Transport指定了執行一個
HTTP 請求的運行機制,假若不指定具體的Transport,默認會使用http.DefaultTransport,
這意味着http.Transport也是能夠自定義的。 net/http包中的http.Transport類型實現了
http.RoundTripper接口。
CheckRedirect 函數指定處理重定向的策略。當使用 HTTP Client 的Get()或者是Head()
方法發送 HTTP 請求時,若響應返回的狀態碼爲 30x (好比 301 / 302 / 303 / 307), HTTP Client 會
在遵循跳轉規則以前先調用這個CheckRedirect函數。
Jar可用於在 HTTP Client 中設定 Cookie, Jar的類型必須實現了 http.CookieJar 接口,
該接口預約義了 SetCookies()和Cookies()兩個方法。若是 HTTP Client 中沒有設定 Jar,
Cookie將被忽略而不會發送到客戶端。實際上,咱們通常都用 http.SetCookie() 方法來設定
Cookie。
使用自定義的http.Client及其Do()方法,咱們能夠很是靈活地控制 HTTP 請求,好比發
送自定義 HTTP Header 或是改寫重定向策略等。建立自定義的 HTTP Client 很是簡單,具體代碼
以下:
client := &http.Client {
CheckRedirect: redirectPolicyFunc,
}
resp, err := client.Get("http://example.com")
// ...
req, err := http.NewRequest("GET", "http://example.com", nil)
// ...
req.Header.Add("User-Agent", "Our Custom User-Agent")
req.Header.Add("If-None-Match", `W/"TheFileEtag"`)
resp, err := client.Do(req)
// ...
自定義 http.Transport
在http.Client 類型的結構定義中,咱們看到的第一個數據成員就是一個 http.Transport
對象,該對象指定執行一個 HTTP 請求時的運行規則。下面咱們來看看 http.Transport 類型
的具體結構:
type Transport struct {
// Proxy指定用於針對特定請求返回代理的函數。
// 若是該函數返回一個非空的錯誤,請求將終止並返回該錯誤。
// 若是Proxy爲空或者返回一個空的URL指針,將不使用代理
Proxy func(*Request) (*url.URL, error)
// Dial指定用於建立TCP鏈接的dail()函數。
// 若是Dial爲空,將默認使用net.Dial()函數
Dial func(net, addr string) (c net.Conn, err error)
// TLSClientConfig指定用於tls.Client的TLS配置。
// 若是爲空則使用默認配置
TLSClientConfig *tls.Config
DisableKeepAlives bool
DisableCompression bool
// 若是MaxIdleConnsPerHost爲非零值,它用於控制每一個host所須要
// 保持的最大空閒鏈接數。若是該值爲空,則使用DefaultMaxIdleConnsPerHost
MaxIdleConnsPerHost int
// ...
}
Proxy func(*Request) (*url.URL, error)
Proxy 指定了一個代理方法,該方法接受一個 *Request 類型的請求實例做爲參數並返回
一個最終的 HTTP 代理。若是 Proxy 未指定或者返回的 *URL 爲零值,將不會有代理被啓用。
Dial func(net, addr string) (c net.Conn, err error)
Dial 指定具體的dial()方法來建立 TCP 鏈接。若是不指定,默認將使用 net.Dial() 方法。
TLSClientConfig *tls.Config
SSL鏈接專用, TLSClientConfig 指定 tls.Client 所用的 TLS 配置信息,若是不指定,
也會使用默認的配置。
DisableKeepAlives bool
是否取消長鏈接,默認值爲 false,即啓用長鏈接。
DisableCompression bool
是否取消壓縮( GZip),默認值爲 false,即啓用壓縮。
MaxIdleConnsPerHost int
指定與每一個請求的目標主機之間的最大非活躍鏈接( keep-alive)數量。若是不指定,默認使
用 DefaultMaxIdleConnsPerHost 的常量值。
除了 http.Transport 類型中定義的公開數據成員之外,它同時還提供了幾個公開的成員
方法。
func(t *Transport) CloseIdleConnections()。該方法用於關閉全部非活躍的
鏈接。
func(t *Transport) RegisterProtocol(scheme string, rt RoundTripper)。
該方法可用於註冊並啓用一個新的傳輸協議,好比 WebSocket 的傳輸協議標準( ws),或
者 FTP、 File 協議等。
func(t *Transport) RoundTrip(req *Request) (resp *Response, err error)。
用於實現 http.RoundTripper 接口。
自定義http.Transport也很簡單,以下列代碼所示:
tr := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: pool},
DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")
靈活的 http.RoundTripper 接口
咱們知道 HTTP Client 是能夠自定義的,而 http.Client 定義的第一
個公開成員就是一個http.Transport 類型的實例 ,且該成所對應的類型必須實現
http.RoundTripper 接口。下面咱們來看看 http.RoundTripper 接口的具體定義:
type RoundTripper interface {
// RoundTrip執行一個單一的HTTP事務,返回相應的響應信息。
// RoundTrip函數的實現不該試圖去理解響應的內容。若是RoundTrip獲得一個響應,
// 不管該響應的HTTP狀態碼如何,都應將返回的err設置爲nil。非空的err
// 只意味着沒有成功獲取到響應。
// 相似地, RoundTrip也不該試圖處理更高級別的協議,好比重定向、認證和
// Cookie等。
//
// RoundTrip不該修改請求內容, 除非了是爲了理解Body內容。每個請求
// 的URL和Header域都應被正確初始化
RoundTrip(*Request) (*Response, error)
}
HTTP服務器
<1>.處理HTTP請求
func ListenAndServe(addr string, handler Handler) error
該方法用於在指定的 TCP 網絡地址 addr 進行監聽,而後調用服務端處理程序來處理傳入的鏈接請求。
該方法有兩個參數:第一個參數 addr 即監聽地址;第二個參數表示服務端處理程序,一般爲空,
這意味着服務端調用 http.DefaultServeMux 進行處理,而服務端編寫的業務邏
輯處理程序 http.Handle() 或 http.HandleFunc() 默認注入 http.DefaultServeMux 中,
具體代碼以下:
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServe(":8080", nil))
自定義 http.Server
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
<2>.處理HTTPS請求
net/http 包還提供 http.ListenAndServeTLS() 方法,用於處理 HTTPS 鏈接請求:
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler)error
ListenAndServeTLS() 和 ListenAndServe()的行爲一致,區別在於只處理HTTPS請求。
此外,服務器上必須存在包含證書和與之匹配的私鑰的相關文件,好比certFile對應SSL證書
文件存放路徑, keyFile對應證書私鑰文件路徑。若是證書是由證書頒發機構簽署的, certFile
參數指定的路徑必須是存放在服務器上的經由CA認證過的SSL證書。
開啓 SSL 監聽服務
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil))
或者
ss := &http.Server{
Addr: ":10443",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(ss.ListenAndServeTLS("cert.pem", "key.pem"))
3.RPC編程
RPC( Remote Procedure Call,遠程過程調用)是一種經過網絡從遠程計算機程序上請求服
務,而不須要了解底層網絡細節的應用程序通訊協議RPC協議構建於TCP或UDP,或者是 HTTP
之上,容許開發者直接調用另外一臺計算機上的程序,而開發者無需額外地爲這個調用過程編寫網
絡通訊相關代碼,使得開發包括網絡分佈式程序在內的應用程序更加容易。
RPC 採用客戶端—服務器( Client/Server)的工做模式。請求程序就是一個客戶端( Client),
而服務提供程序就是一個服務器( Server)。當執行一個遠程過程調用時,客戶端程序首先發送一
個帶有參數的調用信息到服務端,而後等待服務端響應。在服務端,服務進程保持睡眠狀態直到
客戶端的調用信息到達爲止。當一個調用信息到達時,服務端得到進程參數,計算出結果,並向
客戶端發送應答信息,而後等待下一個調用。最後,客戶端接收來自服務端的應答信息,得到進
程結果,而後調用執行並繼續進行
標準庫:net/rpc
net/rpc包容許 RPC 客戶端程序經過網絡或是其餘 I/O 鏈接調用一個遠端對象的公開方法
在 RPC 服務端,可將一個對象註冊爲可訪問的服務,
以後該對象的公開方法就可以以遠程的方式提供訪問。一個 RPC 服務端能夠註冊多個不一樣類型
的對象,但不容許註冊同一類型的多個對象。
一個對象中只有知足以下這些條件的方法,才能被 RPC 服務端設置爲可供遠程訪問:
必須是在對象外部可公開調用的方法(首字母大寫);
必須有兩個參數,且參數的類型都必須是包外部能夠訪問的類型或者是Go內建支持的類型;
第二個參數必須是一個指針;
方法必須返回一個error類型的值。
func (t *T) MethodName(argType T1, replyType *T2) error
該方法( MethodName)的第一個參數表示由 RPC 客戶端傳入的參數,第二個參數表示要返
回給RPC客戶端的結果,該方法最後返回一個 error 類型的值。
RPC 服務端能夠經過調用 rpc.ServeConn 處理單個鏈接請求。多數狀況下,經過 TCP 或
是 HTTP 在某個網絡地址上進行監聽來建立該服務是個不錯的選擇。
Gob是Go的一個序列化數據結構的編碼解碼工具
God是二進制編碼的數據流,而且God流是自解釋的,God沒法跨語言使用,在 Go 的net/rpc包中,
傳輸數據所須要用到的編碼解碼器,默認就是 Gob
RPC 提供的編碼解碼器接口以下:
type ClientCodec interface {
WriteRequest(*Request, interface{}) error
ReadResponseHeader(*Response) error
ReadResponseBody(interface{}) error
Close() error
}
type ServerCodec interface {
ReadRequestHeader(*Request) error
ReadRequestBody(interface{}) error
WriteResponse(*Response, interface{}) error
Close() error
}
接口ClientCodec定義了 RPC 客戶端如何在一個 RPC 會話中發送請求和讀取響應。客戶端程
序經過 WriteRequest() 方法將一個請求寫入到 RPC 鏈接中,並經過 ReadResponseHeader()
和 ReadResponseBody() 讀取服務端的響應信息。當整個過程執行完畢後,再經過 Close() 方
法來關閉該鏈接。
接口ServerCodec定義了 RPC 服務端如何在一個 RPC 會話中接收請求併發送響應。服務端
程序經過 ReadRequestHeader() 和 ReadRequestBody() 方法從一個 RPC 鏈接中讀取請求
信息,而後再經過 WriteResponse() 方法向該鏈接中的 RPC 客戶端發送響應。當完成該過程
後,經過 Close() 方法來關閉鏈接。
4.JSON處理
JSON ( JavaScript Object Notation)是一種比XML更輕量級的數據交換格式,在易於人們閱
讀和編寫的同時,也易於程序解析和生成。儘管JSON是JavaScript的一個子集,但JSON採用徹底
獨立於編程語言的文本格式,且表現爲鍵/值對集合的文本描述形式(相似一些編程語言中的字
典結構),這使它成爲較爲理想的、跨平臺、跨語言的數據交換語言。
能夠用 JSON 傳輸簡單的字符串、數字、布爾值,也能夠傳輸一個數組,或者一個更復雜的複合結構
Go語言內置的encoding/json 標準庫,在Go語言實現JSON的編碼和解碼時,遵循RFC4627協議標準。
<1>.編碼爲json格式
使用json.Marshal()函數能夠對一組數據進行json格式的編碼,json.Marshal()函數的申明
func Marshal(v interface{}) ([]byte, error)
假若有以下一個Book類型的結構體:
type Book struct {
Title string
Authors []string
Publisher string
IsPublished bool
Price float
}
而且有以下一個 Book 類型的實例對象:
gobook := Book{
"Go語言編程",
["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"ituring.com.cn",
true,
9.99
}
而後,咱們可使用 json.Marshal() 函數將gobook實例生成一段JSON格式的文本:
b, err := json.Marshal(gobook)
若是編碼成功, err 將賦於零值 nil,變量b 將會是一個進行JSON格式化以後的[]byte
類型:
b == []byte(`{
"Title": "Go語言編程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99
}`)
Go語言的大多數數據類型均可以轉化爲有效的JSON文本,但channel、 complex和函數這幾種類型除外。
在Go中, JSON轉化先後的數據類型映射以下。
布爾值轉化爲JSON後仍是布爾類型。
浮點數和整型會被轉化爲JSON裏邊的常規數字。
字符串將以UTF-8編碼轉化輸出爲Unicode字符集的字符串,特殊字符好比<將會被轉義爲\u003c。
數組和切片會轉化爲JSON裏邊的數組,但[]byte類型的值將會被轉化爲 Base64 編碼後
的字符串,slice類型的零值會被轉化爲null。
結構體會轉化爲JSON對象,而且只有結構體裏邊以大寫字母開頭的可被導出的字段纔會
被轉化輸出,而這些可導出的字段會做爲JSON對象的字符串索引。
轉化一個map類型的數據結構時,該數據的類型必須是 map[string]T( T能夠是encoding/json 包支持的任意數據類型)。
<2>.json.Unmarshal()函數將JSON格式的文本解碼爲Go裏邊預期的數據結構。
func Unmarshal(data []byte, v interface{}) error
該函數的第一個參數是輸入,即JSON格式的文本(比特序列),第二個參數表示目標輸出容器,用於存放解碼後的值。
json.Unmarshal()函數會根據一個約定的順序查找目標結構中的字段,若是找到
一個即發生匹配。假設一個JSON對象有個名爲"Foo"的索引,要將"Foo"所對應的值填充到目標
結構體的目標字段上, json.Unmarshal()將會遵循以下順序進行查找匹配:
(1) 一個包含Foo標籤的字段;
(2) 一個名爲Foo的字段;
(3) 一個名爲Foo或者Foo或者除了首字母其餘字母不區分大小寫的名爲Foo的字段。
這些字段在類型聲明中必須都是以大寫字母開頭、可被導出的字段。
<3>.解碼未知結構的json數據
Go內建這樣靈活的類型系統,向咱們傳達了一個頗有價值的信息:空接口是通用類型。如
果要解碼一段未知結構的JSON,只需將這段JSON數據解碼輸出到一個空接口便可。在解碼JSON
數據的過程當中, JSON數據裏邊的元素類型將作以下轉換:
JSON中的布爾值將會轉換爲Go中的bool類型;
數值會被轉換爲Go中的float64類型;
字符串轉換後仍是string類型;
JSON數組會轉換爲[]interface{}類型;
JSON對象會轉換爲map[string]interface{}類型;
null值會轉換爲nil。
在Go的標準庫encoding/json包中,容許使用map[string]interface{}和[]interface{}
類型的值來分別存放未知結構的JSON對象或數組,示例代碼以下:
b := []byte(`{
"Title": "Go語言編程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99,
"Sales": 1000000
}`)
var r interface{}
err := json.Unmarshal(b, &r)
在上述代碼中, r被定義爲一個空接口。 json.Unmarshal() 函數將一個JSON對象解碼到
空接口r中,最終r將會是一個鍵值對的 map[string]interface{} 結構:
map[string]interface{}{
"Title": "Go語言編程",
"Authors": ["XuShiwei", "HughLv", "Pandaman", "GuaguaSong", "HanTuo", "BertYuan",
"XuDaoli"],
"Publisher": "ituring.com.cn",
"IsPublished": true,
"Price": 9.99,
"Sales": 1000000
}
要訪問解碼後的數據結構,須要先判斷目標結構是否爲預期的數據類型:
gobook, ok := r.(map[string]interface{})
而後,咱們能夠經過for循環搭配range語句一一訪問解碼後的目標數據:
if ok {
for k, v := range gobook {
switch v2 := v.(type) {
case string:
fmt.Println(k, "is string", v2)
case int:
fmt.Println(k, "is int", v2)
case bool:
fmt.Println(k, "is bool", v2)
case []interface{}:
fmt.Println(k, "is an array:")
for i, iv := range v2 {
fmt.Println(i, iv)
}
default:
fmt.Println(k, "is another type not handle yet")
}
}
}
<4>.json的流式讀寫
Go內建的encoding/json 包還提供Decoder和Encoder兩個類型,用於支持JSON數據的
流式讀寫,並提供NewDecoder()和NewEncoder()兩個函數來便於具體實現:
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder編程
1.數據加密
採用單密鑰的加密算法,咱們稱爲對稱加密,整個系統由以下幾部分構成:須要加密的明文、
加密算法和密鑰。在加密和解密中,使用的密鑰只有一個。常見的單密鑰加密算法有DES、 AES、RC4等。
採用雙密鑰的加密算法,咱們稱爲非對稱加密,整個系統由以下幾個部分構成:須要加密的明文、加密算法、私鑰和公鑰
在該系統中,私鑰和公鑰均可以被用做加密或者解密,可是用私鑰加密的明文,必需要用對應的公鑰解密,
用公鑰加密的明文,必須用對應的私鑰解密。常見的雙密鑰加密算法有RSA等
2.數字簽名
數字簽名,是指用於標記數字文件擁有者、創造者、分發者身份的字符串。數字簽名擁有標記文件身份、分發的不可抵賴性等做用。
經常使用的數字簽名採用了非對稱加密
3.數字證書
4.PKI體系
PKI,全稱公鑰基礎設施,是使用非對稱加密理論,提供數字簽名、加密、數字證書等服務
的體系,通常包括權威認證機構( CA)、數字證書庫、密鑰備份及恢復系統、證書做廢系統、應用接口( API)等。
5.加密通訊
通常的HTTPS是基於SSL( Secure Sockets Layer)協議,SSL是網景公司開發的位於TCP與
HTTP之間的透明安全協議,經過SSL,能夠把HTTP包數據以非對稱加密的形式往返於瀏覽器和站點之間,從而避免被第三方非法獲取。
6、工程管理
1.gotool能夠幫你完成如下幾類工做
<1>.代碼格式化
<2>.代碼質量分析和修復
<3>.單元測試與性能測試
<4>.工程構建
<5>.代碼文檔的提取和展現
<6>.依賴包管理
<7>.執行其餘的包含指令,好比6g等
2.強制性編碼規範
1.命名
任何須要對外暴露的名字必須以大寫字母開頭,不須要對外暴露的則應該以小寫字母開頭。
Go語言明確宣告了擁護駱駝命名法而排斥下劃線法
2.格式化工具
go help fmt
go fmt filename
特色:
<1>.調整了每條語句的位置
<2>.從新擺放花括號的位置
<3>.以製表符縮進代碼
<4>.添加空格
3.遠程import支持
Go語言不只容許咱們導入本地包,還支持在語言級別調用遠程的包。
咱們有一個用於計算CRC32的包託管於Github,那麼能夠這樣寫:
package main
import (
"fmt"
"github.com/myteam/exp/crc32"
)
而後,在執行go build或者go install以前,只須要加這麼一句:
go get github.com/myteam/exp/crc32
當咱們執行完go get以後 ,咱們會在src目錄中看到github.com目錄 ,其中包含myteam/exp/crc32目錄
4.Android 支持
要在Android上執行Go程序,首先要定製出可以生成對應目標二進制文件的Go工具鏈。
在編譯Go源代碼以前,咱們能夠做以下設置:
$ export GOARCH=ARM
$ export GOOS=linux
$ ./all.bash
會生成5g和5l,其中5g是編譯器, 5l是連接器
5.單元測試
Go的單元測試函數分爲兩類:功能測試函數和性能測試函數,分別爲以Test和Benchmark
爲函數名前綴並以*testing.T爲單一參數的函數,
func TestAdd1(t *testing.T)
func BenchmarkAdd1(t *testing.T)
執行功能單元測試很是簡單,直接執行go test命令便可
func BenchmarkAdd1(b *testing.B) {
b.StopTimer() // 暫停計時器
DoPreparation() // 一個耗時較長的準備工做,好比讀文件
b.StartTimer() // 開啓計時器,以前的準備時間未計入總花費時間內
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
性能單元測試的執行與功能測試同樣簡單,不過須要調用時須要增長-test.bench參數,
go test–test.bench add.gojson
配置幾個經常使用的工程構建命令:
構建當前工程( Go Build)
編譯當前打開的Go文件( Go Compile)
運行單元測試( Go Test)
安裝( Go Install)
7.反射
8.類型映射
對於C語言的原生類型, Cgo都會將其映射爲Go語言中的類型: C.char和C.schar(對應於
C語言中的signed char)、 C.uchar(對應於C語言中的unsigned char)、 C.short和C.ushort
(對應於unsigned short)、 C.int和C.uint(對應於unsigned int)、 C.long和C.ulong
(對應於unsigned long)、 C.longlong(對應於C語言中的long long)、 C.ulonglong(對
應於C語言中的unsigned long long類型)以及C.float和C.double。 C語言中的void*指針
類型在Go語言中則用特殊的unsafe.Pointer類型來對應。
C語言中的struct、 union和enum類型,對應到Go語言中都會變成帶這樣前綴的類型名稱:
struct_、 union_和enum_。 比 如 一 個 在 C語 言 中 叫 作person的struct會 被 Cgo 翻 譯 爲
C.struct_person。
9.字符串映射
由於Go語言中有明確的string原生類型,而C語言中用字符數組表示,二者之間的轉換是
一個必須考慮的問題。 Cgo提供了一系列函數來提供支持: C.CString、 C.GoString和
C.GoStringN。須要注意的是,每次轉換都將致使一次內存複製,所以字符串內容實際上是不可
修改的。
10.符號連接
在Go 語言中,通常化的函數原型以下:
package Package
func Method(arg1 ArgType1, arg2 ArgType2, ...) (ret1 RetType1, ret2 RetType2, ...)
func (v ClassType) Method(arg1 ArgType1, arg2 ArgType2, ...) (ret1 RetType1, ret2
RetType2, ...)
func (this *ClassType) Method(arg1 ArgType1, arg2 ArgType2, ...) (ret1 RetType1, ret2
RetType2, ...) // 這種能夠認爲是上一種狀況的特例
因爲 Go 語言並沒有重載,故此語言的「連接符號」由以下信息構成。
Package。 Package 名能夠是多層,例如A/B/C。
ClassType。 很特別的是, Go 語言中 ClassType 能夠是指針,也能夠不是。
Method。
其「連接符號」的組成規則以下:
Package.Method
Package.ClassType·Method
這樣說可能比較抽象,下面舉個實際的例子。假設在 qbox.us/mockfs 模塊中,有以下幾個
函數:
func New(cfg Config) *MockFS
func (fs *MockFS) Mkdir(dir string) (code int, err error)
func (fs MockFS) Foo(bar Bar)
它們的連接符號分別爲:
qbox.us/mockfs.New
qbox.us/mockfs.*MockFS·Mkdir
qbox.us/mockfs.MockFS·Foo
11.協程
協程,也有人稱之爲輕量級線程,具有如下幾個特色。
可以在單一的系統線程中模擬多個任務的併發執行。
在一個特定的時間,只有一個任務在運行,即並不是真正地並行。
被動的任務調度方式,即任務沒有主動搶佔時間片的說法。當一個任務正在執行時,外
部沒有辦法停止它。要進行任務切換,只能經過由該任務自身調用yield()來主動出讓CPU使用權。
每一個協程都有本身的堆棧和局部變量
每一個協程都包含3種運行狀態:掛起、運行和中止。中止一般表示該協程已經執行完成(包
括遇到問題後明確退出執行的狀況),掛起則表示該協程還沒有執行完成,但出讓了時間片,之後
有機會時會由調度器繼續執行。數組
1.控制檯
Scanln 掃描來自標準輸入的文本,將空格分隔的值依次存放到後續的參數內,直到碰到換行
Sscan 和以 Sscan 開頭的函數則是從字符串讀取,除此以外,與 Scanf 相同
inputReader := bufio.NewReader(os.Stdin) //inputReader 是一個指向 bufio.Reader 的指針,建立一個讀取器,並將其與標準輸入綁定。
input, err := inputReader.ReadString('\n') //讀取鍵盤輸入,直到回車鍵(\n)被按下
2.讀文件 os.File瀏覽器