go語言編程 要點總結(二)面向過程編程

變量

變量聲明

var 變量名 變量類型

變量初始化

var v1 int = 10

var v2 = 10

v3 := 10

出現在冒號左側的不應該是被聲明過的變量,而且這種簡短聲明只能出現在函數中

變量賦值

可以採用多重賦值 i, j = x, y

匿名變量

函數返回多個值,如果值想獲得其中的某些可以使用 __, __, nickname := GetName()


常量

字面常量

硬編碼的常量,不用像c語言一樣在末尾加上L來區別是int還是long,go中字面常量是無類型的,只要這個常量在相應類型值域範圍內,就可作爲該類型常量

常量定義

通過const關鍵字來定義

也可以是無類型的

編譯期確定,所以右值不能是執行期才確定值的表達式

預定義常量

true,false,iota

itoa在每一個const關鍵字出現時被置爲0,下一個const出現之前,每出現一次iota,其代表的數字會自動加1

枚舉

通過const後緊跟一對圓括號定義一組常量,而沒有關鍵字enum

const (

Sunday = iota

Monday

...

)

同Go語言的其他符號一樣,以大寫字母開頭的常量在包外可見

類型

基礎類型

  • 布爾類型 bool
  • 整形 int8 byte int16 int uint unitptr等
  • 浮點類型 float32,float64
  • 複數類型 complex64 complex128
  • 字符串 string
  • 字符類型 rune
  • 錯誤類型 eror

複合類型

  • 指針
  • 數組
  • 切片
  • 字典
  • 通道
  • 結構體
  • 接口

布爾

不支持其他類型賦值,不能自動或強制類型轉換

整型

  • int uint uintptr這三個是平臺相關的
  • int和int32是不同類型,編譯器不會自動轉換,可以強制類型轉換
  • 不同類型的值不能進行比較
  • 但是各種類型的整型都可以與字面常量比較
  • 爲運算中的取反,在c中使用~,在go中使用^
  • float32等價與c中float,float64等價與c中的double
  • 沒有指定類型時浮點數被自動推導爲float64
  • 浮點數的比較不能用==,這可能導致不穩定結果,使用math.Fdim函數來進行比較

複數類型

  • complex64由兩個float32構成
  • complex128由兩個float64構成
  • 不指定類型,而推導出來的是complex128
  • value1 = 3.2 + 12i 這樣就可以表示一個複數
  • 也可以用complex(3.2, 12)來表示一個複數
  • 使用內置函數real(z)獲取實部,使用imag(z)獲取虛部

字符串

c/c++中不存在原生字符串,而是使用字符數組,通過字符指針來傳遞

var str1 string聲明一個字符串

可以像數組一樣用下標訪問,但是初始化之後的字符串不能修改

字符串中包含非ASNI的字符,比如中文,則必須把源碼保存爲UTF-8格式

連接操作 x + y

獲取長度 len(s)

取字符 s[i]

for i : =0; i < n; i++ {

} 以字節數組的方式遍歷

for i, ch := range str {

} 以unicode字符遍歷,此時ch類型爲rune

聲明多行字符串時使用"`",它沒有字符轉義,換行也將輸出

字符類型

byte代表utf-8中單個字節,rune代表unicode中單個字符 出於簡化的考慮,多少api假設字符串爲utf-8編碼,使用unicode的較少

數組

[2*N]struct {x, y int32} 類型數組

[1000]*float64 指針數組

[3][5]二維數組

數組長度定義後不可修改,聲明時可以使用常量或者常量表達式

可以使用...省略號聲明一個數組,go語言會自動根據元素個數計算長度,但是中括號不能爲空,那樣就是slice了

len()獲取長度

可以通過下標訪問

也可以通過for i, v := range array {} 的方式訪問

數組是一個值類型,傳遞參數時會發生一次拷貝,函數中使用的也是副本

數組切片

三組切片的數據結構包含三個變量:一個指向原生數組的指針,數組切片中的元素個數,切片已分配的存儲空間

slice並不是真正的動態數組,而是一個引用類型

基於數據創建切片 myArrary[first:last],基於數組全部創建切片 myArray[:]

直接創建 mySlice1 := make([]int, 5, 10) 創建初始元素個數爲5,元素初始值 0,並預留10個存儲空間

mySlice3 := [int{1,2,3,4,5}] 直接初始化5個元素的數組切片,會有一個匿名的數組被創建

for i := 0; i < len(myArray); i++ 逐一遍歷

或者使用range關鍵字 for i, v := range mySlice 遍歷

cap() 返回切片空間大小, len()返回元素個數

mySlice = append(mySlice, 1,2,3) 尾部追加,並生成新的切片

mySlice = append(mySlice, mySlice2...) 省略號是必須的,append語義是從第二個參數開始是追加的元素,省略號的作用是把 mySlice2所有元素打散傳入

newSlice := oldSlice[:] 基於oldSlice創建新的splice 選擇的範圍不能超過oldslice的cap()值,超過len的部分填充爲0

通過copy來複制一個slice到另一個slice,兩個不一樣大小,以較小的元素個數進行復制

append的函數會改變slice所引用的數組內容,從而影響引用同一數組的其他slice。但當slice中沒有剩餘空間時,此時將動態分配新的數組空間。返回的slice數組指針指向這個空間,而原數組的內容將保持不變,其他引用此數組的slice不受影響。

map

聲明一個map :var 變量名 map[key類型] value類型,這種聲明方式需要在使用之前通過make初始化

map的key可以是所有完全定義了==或者!=操作的類型

可以通過make動態創建 myMap = make(map[key類型] value類型)

創建時初始化 myMap = map[string] PersonInfo { "1234" : PersonInfo{}, }

myMap["1234"] = PersonInfo{} 賦值

元素刪除 delete(myMap, "1234") 元素不存在不會有什麼問題

value, ok := myMap["1234"]

if ok {

} 這種方式進行查找

map是無序的,每次打印的map都會不一樣,,只能通過key獲取,不能通過index獲取

map長度是不固定的,和slice一樣,也是引用類型

len函數返回map擁有的key的數量

make和new的區別

make只能創建slice、map和channel,並且返回一個有 初始值(非零)的T類型,而不是*T。

new分配了零值填充的T類型的內存空間,並且返回其地址,即一個*T類型的值。

這是因爲指向數據結構的引用在使用前必須被初始化,例如slice使用前必須初始化他引用的數組。

問題:通過下標返回的值是拷貝,還是引用?


流程控制

  • 條件語句 if、 else 和else if
  • 選擇語句 switch、case和select
  • 循環語句 for和range
  • 跳轉語句 goto

條件語句

條件不需要小括號

無論語句體內有幾條語句,花括號是必須的

左花括號必須與if或else同一行

if之後,條件語句之前,可以添加變量初始化語句,使用分號(;) 分割

在有返回值的函數中,不允許在if else中return,go編譯器找不到終止該函數的return語句

錯誤的例子:

func example(x int) int {

if x == 0 {

return 5

} else{

return x

}

}

選擇語句

左花括號必須和switch同一行

條件表達式不限制爲常量或者整數

單個case中,惡意出現多個結果選項

不需要break來明確退出一個case

只有在case中明確添加fallthrough纔會繼續執行下一個case

可以不設定switch之後的表達式,整個switch和多個if else的邏輯作用相同

循環語句

左花括號必須和for同一行

可以在條件表達式中初始化變量或賦值,多個變量賦值時,只允許使用平行賦值的方式(i,j,k := 1, 2, 3而不是i := 1, j := 2, k := 3)

支持continue和break, break有更高級的用法,可以決定跳出哪曾循環

跳轉語句

goto 跳轉到某個標籤

函數

函數基本組成:關鍵字func,函數名,參數列表,返回值,函數體和返回語句

參數列表和返回值中,多個變量類型相同可以合併,例如func Add(a,b int)

通過import導入函數所在的包,小寫字母開頭的函數只在本包中可見,大寫字母開頭的函數才能被其他包使用

通過(...type) 傳遞不定參數,通過for _, arg := range args 來提取不定參數

函數中調用了其他不定參數的函數,可以原樣傳遞參數,也可以使用切片

func myfunc(args ...int) {

myfunc3(args ...)

myfunc3(args[1:]...)

}

要傳遞任意類型的不定參數,只要將之前的type替換爲interface{}

func Printf(format string, args ...interface{}) { }

通過arg.(type)獲取參數的類型:

func MyPrintf(args ...interface{}) {

for _, arg := range args {

switch arg.(type) {

case int:

case string:

case int64:

default:

}

}

}

多返回值,返回值可以命名,在函數開始的時候初始化爲空,在return不帶任何參數時,會返回對應的返回值變量的值(類似於傳出參數),多個返回值之間用“,”分割,如果函數是首字母大寫的,那麼建議命名返回值變量,這樣有利於生成我文檔

傳遞指針,注意string、slice、map這三種類型的實現類似指針,可以直接傳遞,但函數如果修改slice長度,則仍需傳遞slice指針

不關注某個返回值,可以使用下劃線來跳過這個返回值

函數可以通過type typeName func(input intputType...)(resutlt resultType)的方式來定義類型

匿名函數可以像變量一樣傳遞,

匿名函數也可以直接調用,在函數體最後的右花括號後面緊跟參數列表

閉包

基本概念:閉包是可以包含自由變量的代碼快,這些變量不再這個代碼快內或者任何全局上下文中定義,而在定義代碼快的環境中定義。要執行的代碼快(由於自由變量包含在代碼快中,所以這些自由變量以及她們引用的對象沒有

被釋放)爲自由變量提供綁定的計算環境

價值:函數作爲對象,保存在變量中,通過參數傳遞給其他函數

我的理解,類似與C++中的仿函數對象,只是不需要命名,在外部函數中定義變量,調用外部函數返回內部函數,內部函數訪問了外部函數中定義的變量,因爲有引用所以不能被回收,


錯誤處理

error接口

type error interface {

Error() string

}

自定義error類型

type PathError struct {

Op string

Path string

Err error

}

實現Error方法

func (e *PathError) Error() string {

return e.Op + " " + e.Path + ": " + e.Err.Error()

}

defer 語句遵循先進後出的原則,最後定義的defer先被執行

func panic(interface()) 正常流程終止,執行defer語句,執行完畢後返回到調用函數,並逐層向上執行panic,直至所屬goroutine中所有正在執行的含數據終止

func recover() interface() 用於終止錯誤處理流程,一般應該在defer中調用,截取錯誤處理流程。在未發生一場的goroutine中明確調用回覆過程,會導致該gorutinue所屬的進程打印影廠信息後直接退出

panic作爲最後的手段,代碼中應該沒有或者少有panic


mian和init函數

init函數可用於所有package,main只能用於package main

建議每個package僅使用一個init函數,儘管可以使用多個,但是從可讀性角度來說使用一個i

init和main由go自動調用

init是可選的,但是main是必須的

程序初始化和執行起始於main包,編譯時依次導入依賴包,並初始化包級常量和變量,調用包的init函數,每個包之後被導入一次,等所有導入的包都加載完畢,初始化main包中的常量和變量,調用main的init函數,最後執行main函數


import

可以使用相對路徑和絕對路徑,絕對路徑從gopath/src之後的路徑開始

點操作

import (

. "fmt"

)

這種方式導入包,使用時可以省略包名

別名操作

import (

f "fmt"

)

使用時可以用別名代替包名

_操作

import (

_ "githup.com/ziutek/mymysql/godrv"

)

引入該包,不直接使用包裏的函數,而是調用了該包的init函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章