Golang基础学习总结
出現(xiàn)在:=左側(cè)的變量不應(yīng)該是已經(jīng)被聲明過(guò)的,否則會(huì)導(dǎo)致編譯錯(cuò)誤,比如下面這個(gè) 寫(xiě)法: var i int i := 2 會(huì)導(dǎo)致類(lèi)似如下的編譯錯(cuò)誤: no new variables on left side of := 17、支持多重賦值,i, j = j, i ?兩個(gè)值可以如此簡(jiǎn)單的進(jìn)行交換 ?而不許引入外部變量
18、 我們?cè)谑褂脗鹘y(tǒng)的強(qiáng)類(lèi)型語(yǔ)言編程時(shí),經(jīng)常會(huì)出現(xiàn)這種情況,即在調(diào)用函數(shù)時(shí)為了獲取一個(gè) 值,卻因?yàn)樵摵瘮?shù)返回多個(gè)值而不得不定義一堆沒(méi)用的變量。在Go中這種情況可以通過(guò)結(jié)合使 用多重返回和匿名變量來(lái)避免這種丑陋的寫(xiě)法,讓代碼看起來(lái)更加優(yōu)雅。 假設(shè)GetName()函數(shù)的定義如下,它返回3個(gè)值,分別為firstName、lastName和 nickName: func GetName() (firstName, lastName, nickName string) {??? return "May", "Chan", "Chibi Maruko" } 若只想獲得nickName,則函數(shù)調(diào)用語(yǔ)句可以用如下方式編寫(xiě):?_, _, nickName := GetName() ? 這種用法可以讓代碼非常清晰,基本上屏蔽掉了可能混淆代碼閱讀者視線的內(nèi)容,從而大幅 降低溝通的復(fù)雜度和代碼維護(hù)的難度
19、 在Go語(yǔ)言中,常量是指編譯期間就已知且不可改變的值。常量可以是數(shù)值類(lèi)型(包括整型、 浮點(diǎn)型和復(fù)數(shù)類(lèi)型) 、布爾類(lèi)型、字符串類(lèi)型等。 所謂字面常量(literal) ,是指程序中硬編碼的常量,如: -12 3.14159265358979323846?// 浮點(diǎn)類(lèi)型的常量 ? 3.2+12i ??// 復(fù)數(shù)類(lèi)型的常量 ? true ??// 布爾類(lèi)型的常量 ? "foo"?// 字符串常量 ? 在其他語(yǔ)言中,常量通常有特定的類(lèi)型,比如?12在C語(yǔ)言中會(huì)認(rèn)為是一個(gè)int類(lèi)型的常量。 如果要指定一個(gè)值為?12的long類(lèi)型常量,需要寫(xiě)成-12l,這有點(diǎn)違反人們的直觀感覺(jué)。Go語(yǔ)言 的字面常量更接近我們自然語(yǔ)言中的常量概念,它是無(wú)類(lèi)型的。只要這個(gè)常量在相應(yīng)類(lèi)型的值域 范圍內(nèi),就可以作為該類(lèi)型的常量,比如上面的常量-12,它可以賦值給int、uint、int32、 int64、float32、float64、complex64、complex128等類(lèi)型的變量。
20、常量的定義 通過(guò)const關(guān)鍵字,你可以給字面常量指定一個(gè)友好的名字: const Pi float64 = 3.14159265358979323846 ? const zero = 0.0 ? ? ? ? ? ? // 無(wú)類(lèi)型浮點(diǎn)常量 const ( ? ? size int64 = 1024 ? ? eof = -1 ? ? ? ? ? ? ? ?// 無(wú)類(lèi)型整型常量 ) ? const u, v float32 = 0, 3 ? ?// u = 0.0, v = 3.0,常量的多重賦值 const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 無(wú)類(lèi)型整型和字符串常量 Go的常量定義可以限定常量類(lèi)型,但不是必需的。如果定義常量時(shí)沒(méi)有指定類(lèi)型,那么它 與字面常量一樣,是無(wú)類(lèi)型常量。 常量定義的右值也可以是一個(gè)在編譯期運(yùn)算的常量表達(dá)式,比如 const mask = 1 << 3 由于常量的賦值是一個(gè)編譯期行為, 所以右值不能出現(xiàn)任何需要運(yùn)行期才能得出結(jié)果的表達(dá) 式,比如試圖以如下方式定義常量就會(huì)導(dǎo)致錯(cuò)誤 const Home = os.GetEnv("HOME") 原因很簡(jiǎn)單,os.GetEnv()只有在運(yùn)行期才能知道返回結(jié)果,在編譯期并不能確定,所以 無(wú)法作為常量定義的右值。
21、 Go語(yǔ)言預(yù)定義了這些常量:true、false和iota。?
iota比較特殊,可以被認(rèn)為是一個(gè)可被編譯器修改的常量,在每一個(gè)const關(guān)鍵字出現(xiàn)時(shí)被
重置為0,然后在下一個(gè)const出現(xiàn)之前,每出現(xiàn)一次iota,其所代表的數(shù)字會(huì)自動(dòng)增1。?
從以下的例子可以基本理解iota的用法:?
const?(??????????//?iota被重設(shè)為0?
?c0?=?iota?//?c0?==?0?
?c1?=?iota?//?c1?==?1?
?c2?=?iota??//?c2?==?2??
)???
const?(?
?a?=?1?<<?iota?//?a?==?1?(iota在每個(gè)const開(kāi)頭被重設(shè)為0)?
b?=?1?<<?iota?//?b?==?2?
c?=?1?<<?iota?//?c?==?4??
)???
const?(?
u =?iota?*?42???//?u?==?0? v?float64?=?iota?*?42???//?v?==?42.0?
w ?= iota * 42 ??// w == 84 ?? ) ? const x = iota ????// x == 0 (因?yàn)閕ota又被重設(shè)為0了) ?? const y = iota ????// y == 0 (同上) ? 如果兩個(gè)const的賦值語(yǔ)句的表達(dá)式是一樣的,那么可以省略后一個(gè)賦值表達(dá)式。因此,上 面的前兩個(gè)const語(yǔ)句可簡(jiǎn)寫(xiě)為: const ( ????// iota被重設(shè)為0 ? c0 = iota ??// c0 == 0 ? c1 ??// c1 == 1 ? c2 ????// c2 == 2 ? )??? const ( a = 1 <<iota ????// a == 1 (iota在每個(gè)const開(kāi)頭被重設(shè)為0) ? b???// b == 2 ? c???// c == 4 ? ) 22、 關(guān)于枚舉 ?所有符號(hào) 以大寫(xiě)開(kāi)頭在包外是可見(jiàn)的 ? 小寫(xiě)只能在包內(nèi)部使用 枚舉指一系列相關(guān)的常量,比如下面關(guān)于一個(gè)星期中每天的定義。通過(guò)上一節(jié)的例子,我們 看到可以用在const后跟一對(duì)圓括號(hào)的方式定義一組常量, 這種定義法在Go語(yǔ)言中通常用于定義 枚舉值。Go語(yǔ)言并不支持眾多其他語(yǔ)言明確支持的enum關(guān)鍵字。 下面是一個(gè)常規(guī)的枚舉表示法,其中定義了一系列整型常量: const ( ? ? Sunday = iota ? ? Monday ? ? Tuesday ? ? Wednesday ? ? Thursday ? ? Friday ? ? Saturday ? ? numberOfDays ? ? ? ?// 這個(gè)常量沒(méi)有導(dǎo)出 ? ) ? 同Go語(yǔ)言的其他符號(hào)(symbol)一樣,以大寫(xiě)字母開(kāi)頭的常量在包外可見(jiàn)。 以上例子中numberOfDays為包內(nèi)私有,其他符號(hào)則可被其他包訪問(wèn)。
23、go中的布爾類(lèi)型 只能用 false ?true != ==不能進(jìn)行強(qiáng)制轉(zhuǎn)換? Go語(yǔ)言中的布爾類(lèi)型與其他語(yǔ)言基本一致,關(guān)鍵字也為bool,可賦值為預(yù)定義的true和 false示例代碼如下: var v1 bool v1 = true v2 := (1 == 2) // v2也會(huì)被推導(dǎo)為bool類(lèi)型 布爾類(lèi)型不能接受其他類(lèi)型的賦值,不支持自動(dòng)或強(qiáng)制的類(lèi)型轉(zhuǎn)換。以下的示例是一些錯(cuò)誤 的用法,會(huì)導(dǎo)致編譯錯(cuò)誤: var b bool b = 1 // 編譯錯(cuò)誤 b = bool(1) // 編譯錯(cuò)誤 以下的用法才是正確的: var b bool b = (1!=0) // 編譯正確 ? fmt.Println("Result:", b) // 打印結(jié)果為Result: true
24、Go語(yǔ)言支持以下的幾種比較運(yùn)算符:>、<、==、>=、<=和!=。這一點(diǎn)與大多數(shù)其他語(yǔ)言相?同,與C語(yǔ)言完全一致。 if i!=j { ?} ? //必須帶大括號(hào) ? ? i,j:=1,2 ? ? ? ?if i==j{ ? ? ? ? fmt.Println("i==j"); ? ? ?}else { ? ? ? fmt.Println("i!=j"); ? ? ?} 25、兩個(gè)不同類(lèi)型的值不能比較 比如 int8 int16,只能強(qiáng)制轉(zhuǎn)換 然后再做比較 ? ? ?var a int8 ? ? ?var b int16 ? ? ?a,b=1,2 ? ? ?if int16(a)==b{ ? ? ? ? fmt.Printf("a==b") ? ? ?} ? ? ? 26、雖然兩個(gè) int8 int16不能直接比較 但是 任何整數(shù)類(lèi)型都能和字面常量整數(shù)進(jìn)行比較 ?,但是不能和字符串字面常量進(jìn)行比較 var a int16? ?if a==1{ ? ? ? ?fmt.Printf("a!=\"a\""); ? ? ?}
27、Go語(yǔ)言中的位運(yùn)算 ? ?注意 C語(yǔ)言中的~ 取反。 而Go中變成了^ Go語(yǔ)言支持表2-2所示的位運(yùn)算符。 表 2-2 運(yùn) ?算 ? ? ?含 ?義 ? ? ?樣 ?例 ? x << y ? ?左移 ? ? ? ?124 << 2 ? ?// 結(jié)果為496 ? x >> y ? ??右移 ? ? ? ?124 >> 2 ? ?// 結(jié)果為31 ? x ^ y ? ? ??異或 ? ? ? ??124 ^ 2 ? ? // 結(jié)果為126? ?x & y ?? ??與 ? ? ? ? ? ?124 & 2 ???// 結(jié)果為0 ? x | y ? ? ? ? ??或 ? ? ? ? ??124 | 2 ? ? // 結(jié)果為126 ? ^x ? ? ? ? ?取反 ? ? ? ??^2 ? ? ? ? ?// 結(jié)果為-3 ? Go語(yǔ)言的大多數(shù)位運(yùn)算符與C語(yǔ)言都比較類(lèi)似,除了取反在C語(yǔ)言中是~x,而在Go語(yǔ)言中?是^x
28、關(guān)于浮點(diǎn)數(shù)的操作 ?浮點(diǎn)數(shù) 自動(dòng)推導(dǎo) 是float64即C語(yǔ)言中的double 不能直接和fload32轉(zhuǎn)換 要進(jìn)行強(qiáng)制轉(zhuǎn)換 ? 因?yàn)楦↑c(diǎn)數(shù)的比較精度? 浮點(diǎn)型用于表示包含小數(shù)點(diǎn)的數(shù)據(jù),比如1.234就是一個(gè)浮點(diǎn)型數(shù)據(jù)。Go語(yǔ)言中的浮點(diǎn)類(lèi)型
采用IEEE-754標(biāo)準(zhǔn)的表達(dá)方式。?
1.?浮點(diǎn)數(shù)表示?
Go語(yǔ)言定義了兩個(gè)類(lèi)型float32和float64,其中float32等價(jià)于C語(yǔ)言的float類(lèi)型,
float64等價(jià)于C語(yǔ)言的double類(lèi)型。?
在Go語(yǔ)言里,定義一個(gè)浮點(diǎn)數(shù)變量的代碼如下:?
var?fvalue1?float32?
?
fvalue1?=?12??
fvalue2?:=?12.0?//?如果不加小數(shù)點(diǎn),fvalue2會(huì)被推導(dǎo)為整型而不是浮點(diǎn)型?
對(duì)于以上例子中類(lèi)型被自動(dòng)推導(dǎo)的fvalue2,需要注意的是其類(lèi)型將被自動(dòng)設(shè)為float64,
而不管賦給它的數(shù)字是否是用32位長(zhǎng)度表示的。因此,對(duì)于以上的例子,下面的賦值將導(dǎo)致編譯
錯(cuò)誤:?
fvalue1?=?fvalue2??
對(duì)于以上例子中類(lèi)型被自動(dòng)推導(dǎo)的fvalue2,需要注意的是其類(lèi)型將被自動(dòng)設(shè)為float64, 而不管賦給它的數(shù)字是否是用32位長(zhǎng)度表示的。因此,對(duì)于以上的例子,下面的賦值將導(dǎo)致編譯 錯(cuò)誤: fvalue1 = fvalue2 ? 而必須使用這樣的強(qiáng)制類(lèi)型轉(zhuǎn)換: fvalue1 = float32(fvalue2) 29、自定義精準(zhǔn)的?浮點(diǎn)數(shù)比較 ,由于浮點(diǎn)數(shù)不是一種精確的表達(dá)方式 所以比較精度 可能不準(zhǔn)確 因?yàn)楦↑c(diǎn)數(shù)不是一種精確的表達(dá)方式, 所以像整型那樣直接用==來(lái)判斷兩個(gè)浮點(diǎn)數(shù)是否相等 是不可行的,這可能會(huì)導(dǎo)致不穩(wěn)定的結(jié)果。 下面是一種推薦的替代方案: import "math" ? // p為用戶(hù)自定義的比較精度,比如0.00001 func IsEqual(f1, f2, p float64) bool?{ ?? return math.Fdim(f1, f2) < p ? }
30、 Go語(yǔ)言中的復(fù)數(shù)類(lèi)型 , real 取出 實(shí)部 ?imag取出虛部 ?虛部為0 的復(fù)數(shù) 為純虛數(shù)。 某一類(lèi)數(shù)字可以表示成這種復(fù)數(shù)類(lèi)型 var v1 complex64 ?v1 = 2.5+15i ?v2 := 2.5+15i ?v3 :=complex(2.5,15) ?fmt.Println(v1) ?fmt.Println(v2) ?fmt.Println(v3) ?fmt.Println("real:",real(v1)) ?fmt.Println("real:",imag(v1))
復(fù)數(shù)實(shí)際上由兩個(gè)實(shí)數(shù)(在計(jì)算機(jī)中用浮點(diǎn)數(shù)表示)構(gòu)成,一個(gè)表示實(shí)部(real),一個(gè)表示虛部(imag)。
對(duì)于什么是復(fù)數(shù)可以參考:http://baike.baidu.com/view/10078.htm
復(fù)數(shù)實(shí)際上由兩個(gè)實(shí)數(shù)(在計(jì)算機(jī)中用浮點(diǎn)數(shù)表示)構(gòu)成,一個(gè)表示實(shí)部(real) ,一個(gè)表示
虛部(imag) 。如果了解了數(shù)學(xué)上的復(fù)數(shù)是怎么回事,那么Go語(yǔ)言的復(fù)數(shù)就非常容易理解了。
1. 復(fù)數(shù)表示
復(fù)數(shù)表示的示例如下:
var value1 complex64 ?
?
// 由2個(gè)float32構(gòu)成的復(fù)數(shù)類(lèi)型
?
value1 = 3.2 + 12i
value2 := 3.2 + 12i ?
?
// value2是complex128類(lèi)型
value3 := complex(3.2, 12) ?
// value3結(jié)果同 value2
2. 實(shí)部與虛部
對(duì)于一個(gè)復(fù)數(shù)z = complex(x, y),就可以通過(guò)Go語(yǔ)言?xún)?nèi)置函數(shù)real(z)獲得該復(fù)數(shù)的實(shí)
部,也就是x,通過(guò)imag(z)獲得該復(fù)數(shù)的虛部,也就是y。
更多關(guān)于復(fù)數(shù)的函數(shù),請(qǐng)查閱math/cmplx標(biāo)準(zhǔn)庫(kù)的文檔。
31、Golang中的字符串操作? go中的字符串聲明之后只能獲取 字符不能修改字符 ? 但是可以修改整個(gè)字符串 ? ?var str string ? str = "abc" ? str += "d" ? str="1111" ?fmt.Println(str)? 我們可以獲取單個(gè)字符但是不能修改單個(gè)字符? var str string str = "abc" str += "d" ch:=str[0] fmt.Printf("A:%c",ch) ? ? ?//println不能格式化
32、關(guān)于Go的編碼處理 只支持 Unicode UTF-8格式 ? import strings 這個(gè)包中包含了處理string類(lèi)型的所有工具函數(shù)函數(shù)? Go編譯器支持UTF-8的源代碼文件格式。這意味著源代碼中的字符串可以包含非ANSI的字
符,比如“Hello?world.?你好,世界!?”可以出現(xiàn)在Go代碼中。但需要注意的是,如果你的Go代
碼需要包含非ANSI字符,保存源文件時(shí)請(qǐng)注意編碼格式必須選擇UTF-8。特別是在Windows下一
般編輯器都默認(rèn)存為本地編碼,比如中國(guó)地區(qū)可能是GBK編碼而不是UTF-8,如果沒(méi)注意這點(diǎn)在
編譯和運(yùn)行時(shí)就會(huì)出現(xiàn)一些意料之外的情況。?
字符串的編碼轉(zhuǎn)換是處理文本文檔(比如TXT、XML、HTML等)非常常見(jiàn)的需求,不過(guò)可
惜的是Go語(yǔ)言?xún)H支持UTF-8和Unicode編碼。對(duì)于其他編碼,Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)并沒(méi)有內(nèi)置的編碼轉(zhuǎn)
換支持。不過(guò),所幸的是我們可以很容易基于iconv庫(kù)用Cgo包裝一個(gè)。這里有一個(gè)開(kāi)源項(xiàng)目:
https://github.com/xushiwei/go-iconv
33、在Go中字符串的單個(gè)字符就是 byte類(lèi)型也就是 uint8 一個(gè)字符串的長(zhǎng)度len返回的默認(rèn)是int類(lèi)型也就是平臺(tái)相關(guān)類(lèi)型,我們?cè)谧鱿鄳?yīng)的操作的收 要么自動(dòng)推導(dǎo) 要么進(jìn)行強(qiáng)制轉(zhuǎn)換? ?var str string ? str = "abcdefghijklmn" ? var length int8=int8(len(str)) ? for i:=0 ;i<int(length) ;i++{ ? ? ? fmt.Printf("%c",str[i]) ? }
34、關(guān)于遍歷Unicode字符,每個(gè) unicode的字符類(lèi)型是 rune ? 每個(gè)中文字符在UTF-8中占3個(gè)字節(jié),而不是1個(gè)字節(jié)。 另一種是以Unicode字符遍歷: str := "Hello,世界" for i, ch := range str { ? ? fmt.Println(i, ch)//ch的類(lèi)型為rune } 輸出結(jié)果為: 0 72 1 101 2 108 3 108 4 111 5 44 6 32 7 19990 10 30028 以Unicode字符方式遍歷時(shí),每個(gè)字符的類(lèi)型是rune(早期的Go語(yǔ)言用int類(lèi)型表示Unicode 字符) ,而不是byte。
測(cè)試代碼 package main import "fmt" func main() { ? ?var strUnicode string = "hello,世界" ? ?for i,ch := range strUnicode{ ? ? ? fmt.Println(i,ch) ? ?} } 35、關(guān)于 Go語(yǔ)言中支持的兩種字符類(lèi)型 一種是 byte 實(shí)際上是uint8的別名 ,另一種是unicode類(lèi)型的字符 關(guān)鍵字為 rune? 在Go語(yǔ)言中支持兩個(gè)字符類(lèi)型,一個(gè)是byte(實(shí)際上是uint8的別名) ,代表UTF-8字符串的單個(gè)字節(jié)的值;另一個(gè)是rune,代表單個(gè)Unicode字符。 ? 關(guān)于rune相關(guān)的操作,可查閱Go標(biāo)準(zhǔn)庫(kù)的unicode包。另外unicode/utf8包也提供了?UTF8和Unicode之間的轉(zhuǎn)換。 ? 出于簡(jiǎn)化語(yǔ)言的考慮,Go語(yǔ)言的多數(shù)API都假設(shè)字符串為UTF-8編碼。盡管Unicode字符在標(biāo)?準(zhǔn)庫(kù)中有支持,但實(shí)際上較少使用。?
36、遍歷unicode字符的另一種是 可以用變量占位符去掉不想要的數(shù)據(jù) package main import "fmt" func main() { ? ?var strUnicode string = "hello,世界" ? ?for _,ch := range strUnicode{ ? ? ? fmt.Printf("%c\n",ch) ? ?} }
37、關(guān)于Go語(yǔ)言的指針操作 package main import "fmt" func main() { ? ?var inta int8=3 ; ? ?var pinta*int8=&inta ; ? ?fmt.Printf("%d",*pinta); } 38、 關(guān)于數(shù)組的遍歷 range 遍歷可以選擇忽略 索引 package main import "fmt" func main() { ? byteArr:=[5]byte{1,2,3,4,5} ? for _,val:=range byteArr { ? ? ?fmt.Println(val) ? }?? ?? } //各種數(shù)組的聲明/ [32]byte ??// 長(zhǎng)度為32的數(shù)組,每個(gè)元素為一個(gè)字節(jié) ? [2*N] struct { x, y int32 } // 復(fù)雜類(lèi)型數(shù)組 [1000]*float64 ??// 指針數(shù)組?[3][5]int ? // 二維數(shù)組?[2][2][2]float64 ? ??// 等同于[2]([2]([2]float64))?
/關(guān)于二維數(shù)組的初始化以及聲明.................................. package main import "fmt" func main() { ? td:=[2][5]int{{1,2,3,4,5},{5,4,3,2,1}} ? for _,val:=range td{ ? ? ?for _,vall:=range val{ ? ? ? ? fmt.Println(vall) ? ? ?} ? ? ? } }
39、關(guān)于Go的數(shù)組 是一個(gè)值類(lèi)型,在做為參數(shù)傳遞 或者 做為函數(shù)返回的時(shí)候 都是 數(shù)組的副本,所以不能通過(guò)傳遞 數(shù)組參數(shù)在函數(shù)內(nèi)部 進(jìn)行修改 。、 package main import "fmt" func modify(arr[5]int){ ? ? ?arr[1]=1 ? ? ? fmt.Printf("arr[1]=%d\n",arr[1]) } func main() { ? td:=[5]int{1,2,3,4,5} ? modify(td) ? for _,val:=range td{ ? ? ? ? fmt.Println(val) ? } } //Go Web
40、Go語(yǔ)言中的數(shù)組切片 ? 可以從一個(gè)已存在的數(shù)組創(chuàng)建 也可以直接手動(dòng)創(chuàng)建一個(gè)數(shù)組切片 ? ? 一個(gè)指向原生數(shù)組的指針; ? 數(shù)組切片中的元素個(gè)數(shù); ? 數(shù)組切片已分配的存儲(chǔ)空間。 從底層實(shí)現(xiàn)的角度來(lái)看,數(shù)組切片實(shí)際上仍然使用數(shù)組來(lái)管理元素,因此它們之間的關(guān)系讓 C++程序員們很容易聯(lián)想起STL中std::vector和數(shù)組的關(guān)系。基于數(shù)組,數(shù)組切片添加了一系 列管理功能,可以隨時(shí)動(dòng)態(tài)擴(kuò)充存放空間,并且可以被隨意傳遞而不會(huì)導(dǎo)致所管理的元素被重復(fù)
基于數(shù)組創(chuàng)建切片 package main import "fmt" func modify(arr[]int){ arr[1]=1 fmt.Printf("arr[1]=%d\n",arr[1]) } func main() { td:=[]int{1,2,3,4,5} //基于數(shù)組創(chuàng)建切片 slice:=td[:3] ? ?// ?td[:] ?td[begin:end] 都可以創(chuàng)建數(shù)組切片 ?還可以創(chuàng)建一個(gè)比數(shù)組還大的切片 for _,val:=range slice{ fmt.Println(val) }?? ? }? 41、主動(dòng)創(chuàng)建數(shù)組切片 操作數(shù)組 所有的方法 都是適用于數(shù)組切片 ,合理利用切片能極大提高內(nèi)存操作的速度? 數(shù)組切片支持內(nèi)建的cap()函數(shù)和len()函數(shù)?
從數(shù)組切片創(chuàng)建數(shù)組切片的時(shí)候只要不超過(guò)模板切片的大小那么創(chuàng)建是沒(méi)問(wèn)題的,否則會(huì)報(bào)出數(shù)組切片越界的錯(cuò)誤。
td:=[]int{1,2,3,4,5} ? //這樣創(chuàng)建出來(lái)的實(shí)際上是數(shù)組切片 數(shù)組切片做為參數(shù)傳遞給函數(shù)是可以被修改值的 ,解決了Go中數(shù)組屬于值類(lèi)型 結(jié)果函數(shù)傳遞參數(shù)的時(shí)候值被復(fù)制? package main import "fmt" func modify(arr[]int){ ? ? ?arr[1]=1 ? ? ? fmt.Printf("arr[1]=%d\n",arr[1]) } func main() { ? td:=[]int{1,2,3,4,5} ? //基于數(shù)組創(chuàng)建切片 ? slice:=td[:3] ? ??//從切片創(chuàng)建切片 都可以 ? modify(slice) ? for _,val:=range slice{ ? ? ?fmt.Println(val) ? }??? } 從輸出結(jié)果我們發(fā)現(xiàn)了 數(shù)組切片可以作為參數(shù)傳遞到函數(shù)中并且被函數(shù)所修改 ? 并非一定要事先準(zhǔn)備一個(gè)數(shù)組才能創(chuàng)建數(shù)組切片。Go語(yǔ)言提供的內(nèi)置函數(shù)make()可以用于 靈活地創(chuàng)建數(shù)組切片。下面的例子示范了直接創(chuàng)建數(shù)組切片的各種方法。 創(chuàng)建一個(gè)初始元素個(gè)數(shù)為5的數(shù)組切片,元素初始值為0: mySlice1 := make([]int, 5) ? 創(chuàng)建一個(gè)初始元素個(gè)數(shù)為5的數(shù)組切片,元素初始值為0,并預(yù)留10個(gè)元素的存儲(chǔ)空間: mySlice2 := make([]int, 5, 10) ? 直接創(chuàng)建并初始化包含5個(gè)元素的數(shù)組切片: mySlice3 := []int{1, 2, 3, 4, 5} ? 當(dāng)然,事實(shí)上還會(huì)有一個(gè)匿名數(shù)組被創(chuàng)建出來(lái),只是不需要我們來(lái)操心而已。? 數(shù)組切片支持Go語(yǔ)言?xún)?nèi)置的cap()函數(shù)和len()函數(shù),代碼清單2-2簡(jiǎn)單示范了這兩個(gè)內(nèi)置 函數(shù)的用法。可以看出,cap()函數(shù)返回的是數(shù)組切片分配的空間大小,而len()函數(shù)返回的是 數(shù)組切片中當(dāng)前所存儲(chǔ)的元素個(gè)數(shù) ?動(dòng)態(tài)創(chuàng)建 一個(gè) 初始化五個(gè)0 并且 內(nèi)存儲(chǔ)空間初始化20的 數(shù)組切片 ? td1:=make([]int,5,20) ? fmt.Println(cap(td1)) ? fmt.Println(len(td1))
//為數(shù)組切片動(dòng)態(tài)增加元素 append(td1,1,2,3,4,56,6,7)? //為數(shù)組元素添加數(shù)組切片 append(td1,td2...) ?//一定要加... 附加數(shù)組切片的時(shí)候? 需要注意的是,我們?cè)诘诙€(gè)參數(shù)mySlice2后面加了三個(gè)點(diǎn),即一個(gè)省略號(hào),如果沒(méi)有這個(gè)省 略號(hào)的話(huà),會(huì)有編譯錯(cuò)誤,因?yàn)榘碼ppend()的語(yǔ)義,從第二個(gè)參數(shù)起的所有參數(shù)都是待附加的 元素。因?yàn)閙ySlice中的元素類(lèi)型為int,所以直接傳遞mySlice2是行不通的。加上省略號(hào)相 當(dāng)于把mySlice2包含的所有元素打散后傳入
42. 數(shù)組切片支持內(nèi)容復(fù)制 數(shù)組切片支持Go語(yǔ)言的另一個(gè)內(nèi)置函數(shù)copy(),用于將內(nèi)容從一個(gè)數(shù)組切片復(fù)制到另一個(gè) 數(shù)組切片。如果加入的兩個(gè)數(shù)組切片不一樣大,就會(huì)按其中較小的那個(gè)數(shù)組切片的元素個(gè)數(shù)進(jìn)行 復(fù)制。下面的示例展示了copy()函數(shù)的行為: slice1 := []int{1, 2, 3, 4, 5} ? slice2 := []int{5, 4, 3} ? ? copy(slice2, slice1) // 只會(huì)復(fù)制slice1的前3個(gè)元素到slice2中 copy(slice1, slice2) // 只會(huì)復(fù)制slice2的3個(gè)元素到slice1的前3個(gè)位置
? ?old:=[]int{1,2,3,4,5,6} ? ?newSlice:=[]int{1,3,3} ? ?copy(old,newSlice) ? ?fmt.Println(old) ? ? 43、在map中使用復(fù)雜數(shù)據(jù)類(lèi)型 我們可以使用Go語(yǔ)言?xún)?nèi)置的函數(shù)make()來(lái)創(chuàng)建一個(gè)新map。下面的這個(gè)例子創(chuàng)建了一個(gè)鍵? 類(lèi)型為string、值類(lèi)型為PersonInfo的map: myMap = make(map[string] PersonInfo) 也可以選擇是否在創(chuàng)建時(shí)指定該map的初始存儲(chǔ)能力,下面的例子創(chuàng)建了一個(gè)初始存儲(chǔ)能力 為100的map: myMap = make(map[string] PersonInfo, 100) 關(guān)于存儲(chǔ)能力的說(shuō)明,可以參見(jiàn)2.3.6節(jié)中的內(nèi)容。 創(chuàng)建并初始化map的代碼如下: myMap = map[string] PersonInfo{ ?"1234": PersonInfo{"1", "Jack", "Room 101,..."}, ? }? package main import "fmt" type Info struct{ ? ? name string ? ? age ?int8 } func main() { ? var infoMap map[string] Info ? ? ? ? infoMap=make(map[string] Info) ? infoMap["s1"]= Info{"ydw",11} ? infoMap["s2"]=Info{"xxx",22} ? ? fmt.Println(infoMap) /如果sone 沒(méi)有查找到那么返回值應(yīng)該是nil 實(shí)際上我們只需要判斷 ok是否是 true or false 即可判斷元素是否查找到 ? sone,ok:=infoMap["s1"] ? if ok { ? ? ?fmt.Println("s1 student info exists!",sone.name,":",sone.age) ? }else{ ? ? ?fmt.Println("s1 student info not exists!") ? } } /刪除一個(gè)map用? delete(map,"key") Go語(yǔ)言提供了一個(gè)內(nèi)置函數(shù)delete(),用于刪除容器內(nèi)的元素。下面我們簡(jiǎn)單介紹一下如 何用delete()函數(shù)刪除map內(nèi)的元素: delete(myMap, "1234") 上面的代碼將從myMap中刪除鍵為“1234”的鍵值對(duì)。如果“1234”這個(gè)鍵不存在,那么這個(gè)調(diào) 用將什么都不發(fā)生,也不會(huì)有什么副作用。但是如果傳入的map變量的值是nil,該調(diào)用將導(dǎo)致 程序拋出異常(panic)?
44、對(duì)于函數(shù)的返回值的限制 func returnFunc(num int) int{ ? ? ?if num > 0 { ? ? ? ? return 100 ?//錯(cuò)誤 返回值不能寫(xiě)在if...else之中結(jié)構(gòu)之中 ? ? ?} ? ? ?return 100 }
45、switch case default用法 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") }
46、Go語(yǔ)言的goto 和break Label更加的靈活處理 循環(huán)和跳轉(zhuǎn)
47、自定義復(fù)雜數(shù)據(jù)類(lèi)型 type Info struct{ ? ? name string ? ? age ?int8 } 48、關(guān)于函數(shù)返回 一個(gè)值和函數(shù)返回多個(gè)值 package main import "fmt" func ret1() int{ ? ?return 1 } func ret2()(a int,b int){ ? ?a,b=1,2 ? ?return } func main() { ? ? a,b:=ret2() ?fmt.Println(ret1(),a,b) }
48、Go的大小寫(xiě)規(guī)則 Go牢記這樣的規(guī)則:小寫(xiě)字母開(kāi)頭的函數(shù)只在本包內(nèi)可見(jiàn),大寫(xiě)字母開(kāi)頭的函數(shù)才 能被其他包使用。 這個(gè)規(guī)則也適用于類(lèi)型和變量的可見(jiàn)性。
49、函數(shù)的不定參數(shù) ?實(shí)際上是一種"語(yǔ)法糖"? package main ? import "fmt" func show(args ...int){ ? ? for _,val:= range args{ ? ? ? ?fmt.Println(val) ? ? } } func main() { ? ? show(1,2,3) } 50、不定參數(shù)的傳遞 ? 不定參數(shù)還可以傳遞給其他不定參數(shù)的 函數(shù) ?并且可以打亂傳遞 ... unc myfunc(args ...int) { ? ? // 按原樣傳遞 ? ? myfunc3(args...) ? ? ? // 傳遞片段,實(shí)際上任意的int slice都可以傳進(jìn)去 ? ? myfunc3(args[1:]...) ? }? 51、// ... ? 傳遞任意類(lèi)型的參數(shù) package main import "fmt" func Printfx(args ...interface{}) { ? for _,val:= range args{ ? ? ? ?fmt.Println(val) ? ? } } func main() { ? ? Printfx(1,2,3,"adsd","sdaddf") } 52、Go的不定參數(shù)語(yǔ)法糖 ? Go的不定參數(shù)語(yǔ)法糖會(huì)把 參數(shù)構(gòu)成一個(gè)數(shù)組切片 當(dāng)然你直接傳遞 ?切片數(shù)組是不可以的,因?yàn)樗膮?shù)就是1,2,3,4,5,66,7, ?但是我們可以通過(guò)...的方式打亂 數(shù)組 或者數(shù)組切片 ? ...只可以打亂數(shù)組切片,常規(guī)數(shù)組是個(gè)值類(lèi)型你是無(wú)法操作的
package main import "fmt" func show(args ...int){ ? ? for _,val:= range args{ ? ? ? ?fmt.Println(val) ? ? } } // ... ? func Printfx(args ...interface{}) { ? for _,val:= range args{ ? ? ? ?fmt.Println(val) ? ? } } func main() { ? ? Printfx(1,2,3,"adsd","sdaddf") ? ? slice:=[]int{5,4,3,2,6,7,8} ? ? show(slice...) } 53、通過(guò)傳遞不定參數(shù)獲取 ?任意類(lèi)型不定參數(shù)的類(lèi)型 package main import "fmt" func checkType(args...interface{}){ ? ? for _,val:=range args{ ? ? ? ?switch val.(type){ ? ? ? ? ? case int : ? ? ? ? ? fmt.Println("Type is int!") ? ? ? ? ? case string: ? ? ? ? ? fmt.Println("Type is string!") ? ? ? ? ? default: ? ? ? ? ? fmt.Println("Type is unknow!") ? ? ? ?} ? ? } } func ?main() { ? ? checkType(1,2,3,"aaaa",int64(22)) } 54、使用匿名函數(shù)和閉包 ? ? Go的匿名函數(shù)實(shí)際上就是閉包 ///定義匿名函數(shù) 并且調(diào)用 ? ? funAdd:=func(a,b int)int{ ? ? ? ?return a+b ? ? } ? ? r:=funAdd(11,22) ? ? fmt.Println("a+b=",r) 定義 +調(diào)用匿名函數(shù) 一起 ? ? r=func(a,b int)int{ ? ? ? ? ? return a-b ? ? ? }(11,2) ? ? fmt.Println("a+b=",r) Go閉包 通過(guò)函數(shù)創(chuàng)建匿名函數(shù) 并且返回函數(shù) package main import "fmt" func createFunc()(func(aa,bb,cc int) int){ return func(aa,bb,cc int)int{ return aa+bb+cc } } func ?main() { add:=createFunc() addNum:=add(1,2,3) fmt.Println("addNum:",addNum) }
package main ? import ( "fmt" ) ???? ///函數(shù)的閉包定義 直接調(diào)用 .......閉包內(nèi)部使用的代碼塊外部的變量 只要代碼塊沒(méi)有釋放那么變量不會(huì)被釋放的 func main() { var j int = 5? a := func()(func()) { var i int = 10 return func() { fmt.Printf("i, j: %d, %d\n", i, j) } }() a() j *= 2 a() }
55、函數(shù)多返回值 ???? func ret()(int,int){ return 1,2 } a,b:=ret() fmt.Println("a,b=",a,b)
56、對(duì)于結(jié)構(gòu)類(lèi)型空的值是nil
57、定義結(jié)構(gòu)體一定要加 type,type和C/C++的 typedef 類(lèi)似也可以 起別名 package main import "fmt" type Data struct{ ? ?name string ? ?age ?int } func ?main() { ? ? data:=Data{"a",1} ? ? fmt.Println(data) } ///給結(jié)構(gòu)體起個(gè)別名 package main import "fmt" type Data struct{ name string age ?int } type DData Data func ?main() { data:=DData{"a",1} fmt.Println(data) }
58、Go的defer和資源釋放 相關(guān)問(wèn)題 ? defer語(yǔ)句是按照 先進(jìn)后出的原則,也就是說(shuō)最后一個(gè)defer將會(huì)被先執(zhí)行。? defer字面的意思是延遲執(zhí)行,也就是說(shuō)會(huì)在不需要的時(shí)候自動(dòng)執(zhí)行 而Go語(yǔ)言使用defer 關(guān)鍵字簡(jiǎn)簡(jiǎn)單單地解決了資源何時(shí)釋放的問(wèn)題,比如以下的例子: func CopyFile(dst, src string) (w int64, err error) { srcFile, err := os.Open(src) if err != nil { return } defer srcFile.Close() dstFile, err := os.Create(dstName) if err != nil { return } defer dstFile.Close() return io.Copy(dstFile, srcFile) ? } ? 即使其中的Copy()函數(shù)拋出異常,Go仍然會(huì)保證dstFile和srcFile會(huì)被正常關(guān)閉。 如果覺(jué)得一句話(huà)干不完清理的工作,也可以使用在defer后加一個(gè)匿名函數(shù)的做法: defer func() { // 做你復(fù)雜的清理工作 } () ? 另外,一個(gè)函數(shù)中可以存在多個(gè)defer語(yǔ)句,因此需要注意的是,defer語(yǔ)句的調(diào)用是遵照 先進(jìn)后出的原則,即最后一個(gè)defer語(yǔ)句將最先被執(zhí)行。只不過(guò),當(dāng)你需要為defer語(yǔ)句到底哪 個(gè)先執(zhí)行這種細(xì)節(jié)而煩惱的時(shí)候,說(shuō)明你的代碼架構(gòu)可能需要調(diào)整一下了
59、panic()和recover() panic場(chǎng)景1? package main import "fmt" func ?main() { ? ? defer func(){ ? ? ? ?fmt.Println("hello,defer go") ? ? }() ? ? panic(11111) } recover場(chǎng)景2? package main import "fmt" func ?main() { ? ? defer func(){ ? ? ? ?fmt.Println("hello,defer go") ? ? }() ? ? panic(11111) } Go語(yǔ)言引入了兩個(gè)內(nèi)置函數(shù)panic()和recover()以報(bào)告和處理運(yùn)行時(shí)錯(cuò)誤和程序中的錯(cuò) 誤場(chǎng)景: func panic(interface{}) ? func recover() interface{} ? 當(dāng)在一個(gè)函數(shù)執(zhí)行過(guò)程中調(diào)用panic()函數(shù)時(shí),正常的函數(shù)執(zhí)行流程將立即終止,但函數(shù)中 之前使用defer關(guān)鍵字延遲執(zhí)行的語(yǔ)句將正常展開(kāi)執(zhí)行,之后該函數(shù)將返回到調(diào)用函數(shù),并導(dǎo)致 逐層向上執(zhí)行panic流程,直至所屬的goroutine中所有正在執(zhí)行的函數(shù)被終止。錯(cuò)誤信息將被報(bào) 告,包括在調(diào)用panic()函數(shù)時(shí)傳入的參數(shù),這個(gè)過(guò)程稱(chēng)為錯(cuò)誤處理流程。 從panic()的參數(shù)類(lèi)型interface{}我們可以得知,該函數(shù)接收任意類(lèi)型的數(shù)據(jù),比如整 型、字符串、對(duì)象等。調(diào)用方法很簡(jiǎn)單,下面為幾個(gè)例子: panic(404) ? panic("network broken") ? panic(Error("file not exists")) recover()函數(shù)用于終止錯(cuò)誤處理流程。一般情況下,recover()應(yīng)該在一個(gè)使用defer 關(guān)鍵字的函數(shù)中執(zhí)行以有效截取錯(cuò)誤處理流程。如果沒(méi)有在發(fā)生異常的goroutine中明確調(diào)用恢復(fù) 過(guò)程(使用recover關(guān)鍵字) ,會(huì)導(dǎo)致該goroutine所屬的進(jìn)程打印異常信息后直接退出。 以下為一個(gè)常見(jiàn)的場(chǎng)景。 我們對(duì)于foo()函數(shù)的執(zhí)行要么心里沒(méi)底感覺(jué)可能會(huì)觸發(fā)錯(cuò)誤處理,或者自己在其中明確加 入了按特定條件觸發(fā)錯(cuò)誤處理的語(yǔ)句,那么可以用如下方式在調(diào)用代碼中截取recover(): defer func() { ? ? if r := recover(); r != nil { ? ? ? ? log.Printf("Runtime error caught: %v", r) ? ? } ? }() foo() 無(wú)論foo()中是否觸發(fā)了錯(cuò)誤處理流程,該匿名defer函數(shù)都將在函數(shù)退出時(shí)得到執(zhí)行。假 如foo()中觸發(fā)了錯(cuò)誤處理流程,recover()函數(shù)執(zhí)行將使得該錯(cuò)誤處理過(guò)程終止。如果錯(cuò)誤處 理流程被觸發(fā)時(shí),程序傳給panic函數(shù)的參數(shù)不為nil,則該函數(shù)還會(huì)打印詳細(xì)的錯(cuò)誤信息。?
60、panic()函數(shù)和recover()函數(shù)的調(diào)用具體區(qū)別在哪里 在panic()開(kāi)始錯(cuò)誤處理流程,傳入的類(lèi)型是interface{}任意類(lèi)型 ?, ?如果我們?cè)赿efer 函數(shù)中調(diào)用? recover()函數(shù)那么會(huì)打斷錯(cuò)誤處理流程。 panic的調(diào)用會(huì)終止正常的程序流程
recover()函數(shù)用于終止錯(cuò)誤處理流程。一般情況下,recover()應(yīng)該在一個(gè)使用defer 關(guān)鍵字的函數(shù)中執(zhí)行以有效截取錯(cuò)誤處理流程。如果沒(méi)有在發(fā)生異常的goroutine中明確調(diào)用恢復(fù) 過(guò)程(使用recover關(guān)鍵字) ,會(huì)導(dǎo)致該goroutine所屬的進(jìn)程打印異常信息后直接退出。?
package main import "fmt" func ?main() { //通過(guò)閉包定義 defer匿名函數(shù) 并且直接調(diào)用 ? ? defer func(){ ? ? ?//recover 結(jié)束當(dāng)前錯(cuò)誤處理過(guò)程 ?并且返回 panic的參數(shù),并不結(jié)束其他goroutine的執(zhí)行....... ? ? ? ?if r:=recover() ;r!=nil{ ?? ? ? ? ? ?fmt.Println("recover() called!") ? ? ? ?} ? ? ? ?fmt.Println("hello,defer go") ? ? }() ? ? panic("hello,go") } 61、關(guān)于const 和iota的使用 package main import "fmt" var str string="aaa" const( A=iota B C ) func ?main() { fmt.Println(B) defer func(){ if r:=recover() ;r!=nil{ fmt.Println("recover() called!") fmt.Println(r) } fmt.Println("hello,defer go") }() panic("hello,go") }
62、快速排序算法與數(shù)組切片的使用 package main import "fmt" import "math/rand" /冒泡排序Go實(shí)現(xiàn) 時(shí)間復(fù)雜富 O(n)=n~n^2 func bubbledSort(values []int){ ? var flags bool =true for i:=0 ;i<len(values);i++{ ? flags=true for j:=0;j<len(values)-i-1;j++{ if values[j]>values[j+1] { values[j],values[j+1]=values[j+1],values[j] flags=false } } if flags { break } } } ///快速排序Go實(shí)現(xiàn) func quickSort(values []int,left,right int){ temp := values[left] p := left i, j := left, right for i <= j { for j >= p && values[j] >= temp { j-- } if j >= p { values[p] = values[j] p = j } if values[i] <= temp && i <= p { i++ } if i <= p { values[p] = values[i] p = i } } values[p] = temp if p - left > 1 { quickSort(values, left, p - 1) } if right - p > 1 { quickSort(values, p + 1, right) } } func ?main() { //創(chuàng)建初始化0個(gè)元素 ?容量1000的 切片 如果用索引直接訪問(wèn)切片會(huì)越界的 ?容量必須大于等于 初始化元素個(gè)數(shù) ? ? //val[1]=11 val:=make([]int,0,1000) for i:=0;i<1000;i++{ val=append(val,rand.Intn(1000)) } fmt.Println("冒泡排序前:",val) bubbledSort(val) ? fmt.Println("冒泡排序后:",val) ? }
63、Go中的import和package 等等的關(guān)系? //import只是引入的文件夾而已,,,可以使用相對(duì)路徑或者絕對(duì)路徑 //他會(huì)把文件夾中的所有.go文件引入 ,,,,,, ///package xx 實(shí)際上是 在外不用調(diào)用用的 比如xx.A() 并不是給import使用 ? package內(nèi)部的小寫(xiě)全部是私有 大寫(xiě)全部是公有 //外部包不能和主模塊放到一起會(huì)編譯不過(guò)的 import "./bubble" ?
總結(jié)
以上是生活随笔為你收集整理的Golang基础学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CorelDRAW2023最新版支持WI
- 下一篇: 同伦法