go 是瞬間發(fā)生的動(dòng)作,since 則表示從以前到現(xiàn)在的一段持續(xù)時(shí)間,而瞬間動(dòng)作不可能持續(xù)發(fā)生,只要把瞬間動(dòng)作 go 否定為 not/never go
目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、偃師網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
、數(shù)組
與其他大多數(shù)語言類似,Go語言的數(shù)組也是一個(gè)元素類型相同的定長(zhǎng)的序列。
(1)數(shù)組的創(chuàng)建。
數(shù)組有3種創(chuàng)建方式:[length]Type 、[N]Type{value1, value2, ... , valueN}、[...]Type{value1, value2, ... , valueN} 如下:
復(fù)制代碼代碼如下:
func test5() {
var iarray1 [5]int32
var iarray2 [5]int32 = [5]int32{1, 2, 3, 4, 5}
iarray3 := [5]int32{1, 2, 3, 4, 5}
iarray4 := [5]int32{6, 7, 8, 9, 10}
iarray5 := [...]int32{11, 12, 13, 14, 15}
iarray6 := [4][4]int32{{1}, {1, 2}, {1, 2, 3}}
fmt.Println(iarray1)
fmt.Println(iarray2)
fmt.Println(iarray3)
fmt.Println(iarray4)
fmt.Println(iarray5)
fmt.Println(iarray6)
}
結(jié)果:
[0 0 0 0 0]
[1 2 3 4 5]
[1 2 3 4 5]
[6 7 8 9 10]
[11 12 13 14 15]
[[1 0 0 0] [1 2 0 0] [1 2 3 0] [0 0 0 0]]
我們看數(shù)組 iarray1,只聲明,并未賦值,Go語言幫我們自動(dòng)賦值為0。再看 iarray2 和 iarray3 ,我們可以看到,Go語言的聲明,可以表明類型,也可以不表明類型,var iarray3 = [5]int32{1, 2, 3, 4, 5} 也是完全沒問題的。
(2)數(shù)組的容量和長(zhǎng)度是一樣的。cap() 函數(shù)和 len() 函數(shù)均輸出數(shù)組的容量(即長(zhǎng)度)。如:
復(fù)制代碼代碼如下:
func test6() {
iarray4 := [5]int32{6, 7, 8, 9, 10}
fmt.Println(len(iarray4))
fmt.Println(cap(iarray4))
}
輸出都是5。
(3)使用:
復(fù)制代碼代碼如下:
func test7() {
iarray7 := [5]string{"aaa", `bb`, "可以啦", "叫我說什么好", "()"}
fmt.Println(iarray7)
for i := range iarray7 {
fmt.Println(iarray7[i])
}
}
二、切片
Go語言中,切片是長(zhǎng)度可變、容量固定的相同的元素序列。Go語言的切片本質(zhì)是一個(gè)數(shù)組。容量固定是因?yàn)閿?shù)組的長(zhǎng)度是固定的,切片的容量即隱藏?cái)?shù)組的長(zhǎng)度。長(zhǎng)度可變指的是在數(shù)組長(zhǎng)度的范圍內(nèi)可變。
(1)切片的創(chuàng)建。
切片的創(chuàng)建有4種方式:
1)make ( []Type ,length, capacity )
2) make ( []Type, length)
3) []Type{}
4) []Type{value1 , value2 , ... , valueN }
從3)、4)可見,創(chuàng)建切片跟創(chuàng)建數(shù)組唯一的區(qū)別在于 Type 前的“ [] ”中是否有數(shù)字,為空,則代表切片,否則則代表數(shù)組。因?yàn)榍衅情L(zhǎng)度可變的。如下是創(chuàng)建切片的示例:
復(fù)制代碼代碼如下:
func test8() {
slice1 := make([]int32, 5, 8)
slice2 := make([]int32, 9)
slice3 := []int32{}
slice4 := []int32{1, 2, 3, 4, 5}
fmt.Println(slice1)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
}
輸出為:
[0 0 0 0 0]
[0 0 0 0 0 0 0 0 0]
[]
[1 2 3 4 5]
如上,創(chuàng)造了4個(gè)切片,3個(gè)空切片,一個(gè)有值的切片。
(2)切片與隱藏?cái)?shù)組:
一個(gè)切片是一個(gè)隱藏?cái)?shù)組的引用,并且對(duì)于該切片的切片也引用同一個(gè)數(shù)組。如下示例,創(chuàng)建了一個(gè)切片slice0,并根據(jù)這個(gè)切片創(chuàng)建了2個(gè)切片 slice1 和 slice2:
復(fù)制代碼代碼如下:
func test9() {
slice0 := []string{"a", "b", "c", "d", "e"}
slice1 := slice0[2 : len(slice0)-1]
slice2 := slice0[:3]
fmt.Println(slice0, slice1, slice2)
slice2[2] = "8"
fmt.Println(slice0, slice1, slice2)
}
輸出為:
[a b c d e] [c d] [a b c]
[a b 8 d e] [8 d] [a b 8]
可見,切片slice0 、 slice1 和 slice2是同一個(gè)底層數(shù)組的引用,所以slice2改變了,其他兩個(gè)都會(huì)變。
(3)遍歷、修改切片:
復(fù)制代碼代碼如下:
func test10() {
slice0 := []string{"a", "b", "c", "d", "e"}
fmt.Println("\n~~~~~~元素遍歷~~~~~~")
for _, ele := range slice0 {
fmt.Print(ele, " ")
ele = "7"
}
fmt.Println("\n~~~~~~索引遍歷~~~~~~")
for index := range slice0 {
fmt.Print(slice0[index], " ")
}
fmt.Println("\n~~~~~~元素索引共同使用~~~~~~")
for index, ele := range slice0 {
fmt.Print(ele, slice0[index], " ")
}
fmt.Println("\n~~~~~~修改~~~~~~")
for index := range slice0 {
slice0[index] = "9"
}
fmt.Println(slice0)
}
如上,前三種循環(huán)使用了不同的for range循環(huán),當(dāng)for后面,range前面有2個(gè)元素時(shí),第一個(gè)元素代表索引,第二個(gè)元素代表元素值,使用 “_” 則表示忽略,因?yàn)間o語言中,未使用的值會(huì)導(dǎo)致編譯錯(cuò)誤。
只有一個(gè)元素時(shí),該元素代表索引。
只有用索引才能修改元素。如在第一個(gè)遍歷中,賦值ele為7,結(jié)果沒有作用。因?yàn)樵谠乇闅v中,ele是值傳遞,ele是該切片元素的副本,修改它不會(huì)影響原本值,而在第四個(gè)遍歷——索引遍歷中,修改的是該切片元素引用的值,所以可以修改。
結(jié)果為:
~~~~~~元素遍歷~~~~~~
a b c d e
~~~~~~索引遍歷~~~~~~
a b c d e
~~~~~~元素索引共同使用~~~~~~
aa bb cc dd ee
~~~~~~修改~~~~~~
[9 9 9 9 9]
(4)、追加、復(fù)制切片:
復(fù)制代碼代碼如下:
func test11() {
slice := []int32{}
fmt.Printf("slice的長(zhǎng)度為:%d,slice為:%v\n", len(slice), slice)
slice = append(slice, 12, 11, 10, 9)
fmt.Printf("追加后,slice的長(zhǎng)度為:%d,slice為:%v\n", len(slice), slice)
slicecp := make([]int32, (len(slice)))
fmt.Printf("slicecp的長(zhǎng)度為:%d,slicecp為:%v\n", len(slicecp), slicecp)
copy(slicecp, slice)
fmt.Printf("復(fù)制賦值后,slicecp的長(zhǎng)度為:%d,slicecp為:%v\n", len(slicecp), slicecp)
}
追加、復(fù)制切片,用的是內(nèi)置函數(shù)append和copy,copy函數(shù)返回的是最后所復(fù)制的元素的數(shù)量。
(5)、內(nèi)置函數(shù)append
內(nèi)置函數(shù)append可以向一個(gè)切片后追加一個(gè)或多個(gè)同類型的其他值。如果追加的元素?cái)?shù)量超過了原切片容量,那么最后返回的是一個(gè)全新數(shù)組中的全新切片。如果沒有超過,那么最后返回的是原數(shù)組中的全新切片。無論如何,append對(duì)原切片無任何影響。如下示例:
復(fù)制代碼代碼如下:
func test12() {
slice := []int32{1, 2, 3, 4, 5, 6}
slice2 := slice[:2]
_ = append(slice2, 50, 60, 70, 80, 90)
fmt.Printf("slice為:%v\n", slice)
fmt.Printf("操作的切片:%v\n", slice2)
_ = append(slice2, 50, 60)
fmt.Printf("slice為:%v\n", slice)
fmt.Printf("操作的切片:%v\n", slice2)
}
如上,append方法用了2次,結(jié)果返回的結(jié)果完全不同,原因是第二次append方法追加的元素?cái)?shù)量沒有超過 slice 的容量。而無論怎樣,原切片slice2都無影響。結(jié)果:
slice為:[1 2 3 4 5 6]
操作的切片:[1 2]
slice為:[1 2 50 60 5 6]
操作的切片:[1 2]
在Go語言中有一些調(diào)試技巧能幫助我們快速找到問題,有時(shí)候你想盡可能多的記錄異常但仍覺得不夠,搞清楚堆棧的意義有助于定位Bug或者記錄更完整的信息。
本文將討論堆棧跟蹤信息以及如何在堆棧中識(shí)別函數(shù)所傳遞的參數(shù)。
Functions
先從這段代碼開始:
Listing 1
01 package main
02
03 func main() {
04 ? ? slice := make([]string, 2, 4)
05 ? ? Example(slice, "hello", 10)
06 }
07
08 func Example(slice []string, str string, i int) {
09 ? ? panic("Want stack trace")
10 }
Example函數(shù)定義了3個(gè)參數(shù),1個(gè)string類型的slice, 1個(gè)string和1個(gè)integer, 并且拋出了panic,運(yùn)行這段代碼可以看到這樣的結(jié)果:
Listing 2
Panic: Want stack trace
goroutine 1 [running]:
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:9 +0x64
main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:5 +0x85
goroutine 2 [runnable]:
runtime.forcegchelper()
/Users/bill/go/src/runtime/proc.go:90
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 3 [runnable]:
runtime.bgsweep()
/Users/bill/go/src/runtime/mgc0.go:82
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
堆棧信息中顯示了在panic拋出這個(gè)時(shí)間所有的goroutines狀態(tài),發(fā)生的panic的goroutine會(huì)顯示在最上面。
Listing 3
01 goroutine 1 [running]:
02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:9 +0x64
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:5 +0x85
第1行顯示最先發(fā)出panic的是goroutine 1, 第二行顯示panic位于main.Example中, 并能定位到該行代碼,在本例中第9行引發(fā)了panic。
下面我們關(guān)注參數(shù)是如何傳遞的:
Listing 4
// Declaration
main.Example(slice []string, str string, i int)
// Call to Example by main.
slice := make([]string, 2, 4)
Example(slice, "hello", 10)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
這里展示了在main中帶參數(shù)調(diào)用Example函數(shù)時(shí)的堆棧信息,比較就能發(fā)現(xiàn)兩者的參數(shù)數(shù)量并不相同,Example定義了3個(gè)參數(shù),堆棧中顯示了6個(gè)參數(shù)。現(xiàn)在的關(guān)鍵問題是我們要弄清楚它們是如何匹配的。
第1個(gè)參數(shù)是string類型的slice,我們知道在Go語言中slice是引用類型,即slice變量結(jié)構(gòu)會(huì)包含三個(gè)部分:指針、長(zhǎng)度(Lengthe)、容量(Capacity)
Listing 5
// Slice parameter value
slice := make([]string, 2, 4)
// Slice header values
Pointer: ?0x2080c3f50
Length: ? 0x2
Capacity: 0x4
// Declaration
main.Example(slice []string, str string, i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
因此,前面3個(gè)參數(shù)會(huì)匹配slice, 如下圖所示:
Figure 1
figure provided by Georgi Knox
我們現(xiàn)在來看第二個(gè)參數(shù),它是string類型,string類型也是引用類型,它包括兩部分:指針、長(zhǎng)度。
Listing 6
// String parameter value
"hello"
// String header values
Pointer: 0x425c0
Length: ?0x5
// Declaration
main.Example(slice []string,?str string, i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4,?0x425c0, 0x5, 0xa)
可以確定,堆棧信息中第4、5兩個(gè)參數(shù)對(duì)應(yīng)代碼中的string參數(shù),如下圖所示:
Figure 2
figure provided by Georgi Knox
最后一個(gè)參數(shù)integer是single word值。
Listing 7
// Integer parameter value
10
// Integer value
Base 16: 0xa
// Declaration
main.Example(slice []string, str string,?i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5,?0xa)
現(xiàn)在我們可以匹配代碼中的參數(shù)到堆棧信息了。
Figure 3
figure provided by Georgi Knox
Methods
如果我們將Example作為結(jié)構(gòu)體的方法會(huì)怎么樣呢?
Listing 8
01 package main
02
03 import "fmt"
04
05 type trace struct{}
06
07 func main() {
08 ? ? slice := make([]string, 2, 4)
09
10 ? ? var t trace
11 ? ? t.Example(slice, "hello", 10)
12 }
13
14 func (t *trace) Example(slice []string, str string, i int) {
15 ? ? fmt.Printf("Receiver Address: %p\n", t)
16 ? ? panic("Want stack trace")
17 }
如上所示修改代碼,將Example定義為trace的方法,并通過trace的實(shí)例t來調(diào)用Example。
再次運(yùn)行程序,會(huì)發(fā)現(xiàn)堆棧信息有一點(diǎn)不同:
Listing 9
Receiver Address:?0x1553a8
panic: Want stack trace
01 goroutine 1 [running]:
02 main.(*trace).Example(0x1553a8, 0x2081b7f50, 0x2, 0x4, 0xdc1d0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:16 +0x116
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:11 +0xae
首先注意第2行的方法調(diào)用使用了pointer receiver,在package名字和方法名之間多出了"*trace"字樣。另外,參數(shù)列表的第1個(gè)參數(shù)標(biāo)明了結(jié)構(gòu)體(t)地址。我們從堆棧信息中看到了內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。
Packing
如果有多個(gè)參數(shù)可以填充到一個(gè)single word, 則這些參數(shù)值會(huì)合并打包:
Listing 10
01 package main
02
03 func main() {
04 ? ? Example(true, false, true, 25)
05 }
06?
07 func Example(b1, b2, b3 bool, i uint8) {
08 ? ? panic("Want stack trace")
09 }
這個(gè)例子修改Example函數(shù)為4個(gè)參數(shù):3個(gè)bool型和1個(gè)八位無符號(hào)整型。bool值也是用8個(gè)bit表示,所以在32位和64位架構(gòu)下,4個(gè)參數(shù)可以合并為一個(gè)single word。
Listing 11
01 goroutine 1 [running]:
02 main.Example(0x19010001)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:8 +0x64
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:4 +0x32
這是本例的堆棧信息,看下圖的具體分析:
Listing 12
// Parameter values
true, false, true, 25
// Word value
Bits ? ?Binary ? ? ?Hex ? Value
00-07 ? 0000 0001 ??01? ??true
08-15 ? 0000 0000 ??00? ? false
16-23 ? 0000 0001 ??01? ? true
24-31 ? 0001 1001 ??19? ? 25
// Declaration
main.Example(b1, b2, b3 bool, i uint8)
// Stack trace
main.Example(0x19010001)
以上展示了參數(shù)值是如何匹配到4個(gè)參數(shù)的。當(dāng)我們看到堆棧信息中包括十六進(jìn)制值,需要知道這些值是如何傳遞的。
定義一個(gè)切片,然后讓切片去引用一個(gè)已經(jīng)創(chuàng)建好的數(shù)組?;菊Z法如下:
索引1:切片引用的起始元素位
索引2:切片只引用該元素位之前的元素
例程如下:
在該方法中,我們未指定容量cap,這里的值為5是系統(tǒng)定義的。
在方法一中,可以用arr數(shù)組名來操控?cái)?shù)組中的元素,也可以通過slice切片來操控?cái)?shù)組中的元素。切片是直接引用數(shù)組,數(shù)組是事先存在的,程序員是可見的。
通過 make 來創(chuàng)建切片,基本語法如下:
make函數(shù)第三個(gè)參數(shù)cap即容量是可選的,如果一定要自己注明的話,要注意保證cap≥len。
用該方法可以 指定切片的大小(len)和容量(cap)
例程如下:
由于未賦值系統(tǒng)默認(rèn)將元素值置為0,即:
數(shù)值類型數(shù)組:????默認(rèn)值為 0
字符串?dāng)?shù)組:? ? ? ?默認(rèn)值為 ""
bool數(shù)組:? ? ? ? ? ?默認(rèn)值為 false
在方法二中,通過make方式創(chuàng)建的切片對(duì)應(yīng)的數(shù)組是由make底層維護(hù),對(duì)外不可見,即只能通過slice去訪問各個(gè)元素。
定義一個(gè)切片,直接就指定具體數(shù)組,使用原理類似于make的方式。
例程如下:
PHP的數(shù)組是數(shù)列Array,列表List,散列表/關(guān)聯(lián)數(shù)組/字典Hashtable的聚合體。
是一個(gè)非常高級(jí)的數(shù)據(jù)結(jié)構(gòu)。也是一個(gè)優(yōu)秀的設(shè)計(jì)。
有一套數(shù)組功能函數(shù)支持php的數(shù)組。
C數(shù)組只是一個(gè)"固定長(zhǎng)度、固定類型"的數(shù)列Array,實(shí)現(xiàn)簡(jiǎn)單,功能原始。有數(shù)列的隨機(jī)操作快的長(zhǎng)處,也有數(shù)列的增、刪低效的毛病
如果要比較,PHP的數(shù)組應(yīng)該和C++的STL有一比,功能類似。
本文題目:go語言slice評(píng)分 Go slice
當(dāng)前網(wǎng)址:http://jinyejixie.com/article36/dodhdsg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、、軟件開發(fā)、網(wǎng)站營(yíng)銷、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)