濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > Go語(yǔ)言中的復(fù)合類型詳細(xì)介紹

Go語(yǔ)言中的復(fù)合類型詳細(xì)介紹

熱門(mén)標(biāo)簽:外呼系統(tǒng)多少錢一年 經(jīng)常接到推銷電話機(jī)器人的電話 海外照相館地圖標(biāo)注入駐 外呼系統(tǒng)如何接收服務(wù)密碼 滁州自建外呼系統(tǒng) 客服級(jí)電銷機(jī)器人 智能營(yíng)銷軟件 工商信用卡外呼系統(tǒng)教程 旅游廁所如何電子地圖標(biāo)注

golang復(fù)合類型包括:結(jié)構(gòu)體、數(shù)組、切片、Maps。

1、數(shù)組

數(shù)組

golang中的數(shù)組與C語(yǔ)言中的數(shù)組差異很大,倒更類似Pascal中的數(shù)組。 (Slice,下個(gè)話題,有些像C語(yǔ)言中的數(shù)組)

復(fù)制代碼 代碼如下:

var ar [3]int

聲明ar為一個(gè)擁有三個(gè)整型數(shù)的數(shù)組,所有元素初始化為0。

大小是類型的一個(gè)組成部分。

內(nèi)置的函數(shù)len可以用于獲取數(shù)組大?。?/p>

復(fù)制代碼 代碼如下:

len(ar) = 3

數(shù)組是值類型

golang中的數(shù)組是值,而非C語(yǔ)言中的隱式指針。你可以獲得數(shù)組的地址,并生成一個(gè)指向數(shù)組的指針(例如,將其高效地傳遞給函數(shù)):

復(fù)制代碼 代碼如下:

func f(a [3]int) { fmt.Println(a) }  
func fp(a *[3]int) { fmt.Println(a) }  
 
func main() {  
    var ar [3] int 
    f(ar) // 傳遞一個(gè)ar的拷貝  
    fp(ar) // 傳遞一個(gè)指向ar的指針  

輸出結(jié)果:

復(fù)制代碼 代碼如下:

[0 0 0]

[0 0 0]

數(shù)組字面值

所有的符合類型都有相同的值創(chuàng)建語(yǔ)法。以數(shù)組為例,其語(yǔ)法如下:

3個(gè)整數(shù)的數(shù)組:

復(fù)制代碼 代碼如下:

[3]int{1, 2, 3}

10個(gè)整數(shù)的數(shù)組,前三個(gè)元素不是0:

復(fù)制代碼 代碼如下:

[10]int{ 1, 2, 3}

不想數(shù)?使用…代表長(zhǎng)度:

復(fù)制代碼 代碼如下:

[...]int{1, 2, 3}

不想初始化所有值?使用key:value對(duì):

復(fù)制代碼 代碼如下:

[10]int{2:1, 3:1, 5:1, 7:1}

指向數(shù)組字面值的指針

你可以獲取數(shù)組字面值的地址,這樣可以得到一個(gè)指向新建數(shù)組實(shí)例的指針:

復(fù)制代碼 代碼如下:

func fp(a *[3]int) { fmt.Println(a) }  
func main() {  
    for i := 0; i 3; i++ {  
        fp([3]int{i, i*i, i*i*i})  
    }  

輸出結(jié)果:

復(fù)制代碼 代碼如下:

[0 0 0]
[1 1 1]
[2 4 8]

2、切片(Slice)

切片

切片是對(duì)數(shù)組中某一段的引用。

切片比普通數(shù)組應(yīng)用得更多也更廣泛。

切片使用的代價(jià)很低。

一個(gè)切片類型很像一個(gè)沒(méi)有大小的數(shù)組類型:

復(fù)制代碼 代碼如下:

var a []int

內(nèi)置的len(a)可以返回切片中元素的個(gè)數(shù)。

通過(guò)對(duì)數(shù)組或切片進(jìn)行"切片",我們可以創(chuàng)建一個(gè)新切片:

復(fù)制代碼 代碼如下:

a = ar[7:9]

a(上面例子中的a)的有效下標(biāo)值是0和1;len(a) == 2。

切片速記

當(dāng)對(duì)數(shù)組進(jìn)行切片時(shí),第一個(gè)下標(biāo)值默認(rèn)是0:

ar[:n]等價(jià)于a[0:n]。

第二個(gè)下標(biāo)值默認(rèn)為len(array/slice):

ar[n:]等價(jià)于ar[n:len(ar)]。

因此由數(shù)組創(chuàng)建切片時(shí):

ar[:]等價(jià)于ar[0:len(ar)]。

切片引用數(shù)組

概念上:

復(fù)制代碼 代碼如下:

type Slice struct {
base *elemType // 指向0th元素的指針
len int // 切片中元素的數(shù)量
cap int // 切片可以容納元素的數(shù)量
}

數(shù)組:

復(fù)制代碼 代碼如下:

ar: 7 1 5 4 3 8 7 2 11 5 3

切片:

復(fù)制代碼 代碼如下:

a = ar[7:9] :base = ar[7](指向ar中的2) len = 2 cap = 4

創(chuàng)建切片

切片字面值看起來(lái)像沒(méi)有指定大小的數(shù)組字面值:

復(fù)制代碼 代碼如下:

var slice = []int{1,2,3,4,5}

上面代碼創(chuàng)建了一個(gè)長(zhǎng)度為5的數(shù)組并創(chuàng)建一個(gè)切片用于引用這個(gè)數(shù)組。

我們可以使用內(nèi)置的make函數(shù)分配一個(gè)切片(底層實(shí)際是個(gè)數(shù)組):

復(fù)制代碼 代碼如下:

var s100 = make([]int, 100) // slice: 100 ints

為何用make而不是用new?因?yàn)槲覀冃枰獎(jiǎng)?chuàng)建切片,而不僅僅是為了分配內(nèi)存。注意make([]int, 10)返回[]int,而new([]int)返回*[]int。

使用make創(chuàng)建切片、map以及channel。

切片容量

切片是對(duì)底層數(shù)組的一個(gè)引用。因此存在一些在數(shù)組里但卻沒(méi)在切片引用的范圍內(nèi)的元素。

內(nèi)置的函數(shù)cap(capacity)用于報(bào)告切片可能增長(zhǎng)到多長(zhǎng)。

復(fù)制代碼 代碼如下:

var ar = [10]int{0,1,2,3,4,5,6,7,8,9}
var a = ar[5:7] // 引用子數(shù)組{5,6}

len(a) = 2,cap(a) = 5,現(xiàn)在我們可以重新切片:

復(fù)制代碼 代碼如下:

a = a[0:4] // 引用子數(shù)組 {5,6,7,8}

len(a)現(xiàn)在是4,而cap(a)依舊是5。

調(diào)整切片大小

切片可被當(dāng)作可增長(zhǎng)的數(shù)組用。使用make分配一個(gè)切片,并指定其長(zhǎng)度和容量。當(dāng)要增長(zhǎng)時(shí),我們可以做重新切片:

復(fù)制代碼 代碼如下:

var sl = make([]int, 0, 100) // 長(zhǎng)度 0, 容量 100  
func appendToSlice(i int, sl []int) []int {  
    if len(sl) == cap(sl) { error(…) }  
    n := len(sl)  
    sl = sl[0:n+1] // 長(zhǎng)度增加1  
    sl[n] = i  
    return sl  
}

因此,sl的長(zhǎng)度總是元素的個(gè)數(shù),但其容量可根據(jù)需要增加。

這種手法代價(jià)很小,并且是Go語(yǔ)言中的慣用法。

切片使用的代價(jià)很小

你可以根據(jù)需要自由地分配和調(diào)整切片大小。它們的傳遞僅需要很小的代價(jià);不必分配。

記住它們是引用,因此下層的存儲(chǔ)可以被修改。

例如,I/O使用切片,而不是計(jì)數(shù):

復(fù)制代碼 代碼如下:

func Read(fd int, b []byte) int 
var buffer [100]byte  
    for i := 0; i 100; i++ {  
    // 每次向Buffer中填充一個(gè)字節(jié)  
    Read(fd, buffer[i:i+1]) // no allocation here  

拆分一個(gè)Buffer:

復(fù)制代碼 代碼如下:

header, data := buf[:n], buf[n:]

字符串也可以被切片,而且效率相似。

3、Maps

maps

Map是另外一種引用類型。它們是這樣聲明的:

復(fù)制代碼 代碼如下:

var m map[string]float64

這里聲明了一個(gè)map,索引key的類型為string,值類型為float64。這類似于C++中的類型*mapstring, float64>。

對(duì)于給定map m,len(m)返回key的數(shù)量。

map的創(chuàng)建

和創(chuàng)建一個(gè)切片一樣,一個(gè)map變量是一個(gè)空引用;在可以使用它之前,應(yīng)先要向里面放入一些內(nèi)容。

三種方式:

1) 字面值:逗號(hào)分隔的key:value對(duì)列表

復(fù)制代碼 代碼如下:

m = map[string]float64{"1":1, "pi":3.1415}

2) 創(chuàng)建
復(fù)制代碼 代碼如下:

m = make(map[string]float64) // make not new

3) 賦值
復(fù)制代碼 代碼如下:

var m1 map[string]float64
m1 = m // m1和m現(xiàn)在引用相同的map

map索引

(接下來(lái)的幾個(gè)例子全都使用:

復(fù)制代碼 代碼如下:

m = map[string]float64{"1":1, "pi":3.1415})

訪問(wèn)一個(gè)元素;如果該元素不存在,則得到對(duì)應(yīng)map value類型的零值:
復(fù)制代碼 代碼如下:

one := m["1"]
zero := m["not present"] // zero被置為0.0.

設(shè)置一個(gè)元素的值(兩次設(shè)置將更新為最新值)
復(fù)制代碼 代碼如下:

m["2"] = 2
m["2"] = 3 // 思維混亂

測(cè)試存在性

要測(cè)試一個(gè)map中是否存在某個(gè)key,我們可以使用一個(gè)多項(xiàng)賦值的"comma, om"形式:

復(fù)制代碼 代碼如下:

m = map[string]float64{"1":1, "pi":3.1415}

var value float64
var present bool

value, present = m[x]

或者按慣例:

復(fù)制代碼 代碼如下:

value, ok := m[x] // "comma ok" 形式

如果map中存在x這個(gè)key,布爾變量會(huì)被設(shè)置為true;value會(huì)被賦值為map中key對(duì)應(yīng)的值。相反,布爾變量會(huì)被設(shè)置為false,value被設(shè)置為相應(yīng)值類型的零值。

刪除

使用多元賦值可以刪除map中的一個(gè)值:

復(fù)制代碼 代碼如下:

m = map[string]float64{"1":1.0, "pi":3.1415}

var keep bool
var value float64
var x string = f()

m[x] = v, keep

如果keep的值為true,則將v賦值到map中;如果keep為false,則刪除map中的key x。因此刪除一個(gè)key:

復(fù)制代碼 代碼如下:

m[x] = 0, false // 從map中刪除x

譯注:Go 1中上述的刪除方式已被取消,取而代之的是delete(m, x)。

for和range

對(duì)于數(shù)組、切片和map(以及我們?cè)诘谌糠謱⒁吹降母囝愋停琭or循環(huán)提供了一種特殊的語(yǔ)法用于迭代訪問(wèn)其中的元素。

復(fù)制代碼 代碼如下:

m := map[string]float64{"1":1.0, "pi":3.1415}

for key, value := range m {
fmt.Printf("key %s, value %g\n", key, value)
}

只用一個(gè)變量,我們可以獲得key:

復(fù)制代碼 代碼如下:

for key = range m {
fmt.Printf("key %s\n", key)
}

變量可以用:=賦值或聲明。

對(duì)于數(shù)組和切片來(lái)說(shuō),通過(guò)這種方式我們可以獲得元素的下標(biāo)以及元素值。

將range用于字符串

將for range用于字符串時(shí),實(shí)際迭代的元素是Unicode碼點(diǎn)(code point),而不是字節(jié)(對(duì)字節(jié),可使用[]byte或使用標(biāo)準(zhǔn)的for語(yǔ)句)。我們假設(shè)字符串包

含使用UTF-8編碼的字符。

下面循環(huán):

復(fù)制代碼 代碼如下:

s := "[\u00ff\u754c]"
for i, c := range s {
fmt.Printf("%d:%q ", i, c) // %q for 'quoted'
}

輸出:0:'[' 1:'ÿ' 3:'界' 6:']'

如果遇到了錯(cuò)誤的UTF-8碼點(diǎn),這個(gè)字符將被設(shè)置為U+FFFD,下標(biāo)向后移動(dòng)一個(gè)字節(jié)。

4、Structs

structs

對(duì)于Go中的struct,你應(yīng)該感覺(jué)十分熟悉:簡(jiǎn)單的數(shù)據(jù)字段聲明。

復(fù)制代碼 代碼如下:

var p struct {
x, y float64
}

更常用的是:

復(fù)制代碼 代碼如下:

type Point struct {
x, y float64
}
var p Point

struct允許程序員定義內(nèi)存布局。

struct是值類型

struct是值類型,new(StructType)返回一個(gè)指向零值的指針(分配的內(nèi)存都被置0)。

復(fù)制代碼 代碼如下:

type Point struct {
x, y float64
}
var p Point
p.x = 7
p.y = 23.4
var pp *Point = new(Point)
*pp = p
pp.x = Pi // (*pp).x的語(yǔ)法糖

對(duì)于結(jié)構(gòu)體指針,沒(méi)有->符號(hào)可用。Go提供了間接的方式。

創(chuàng)建結(jié)構(gòu)體

結(jié)構(gòu)體是值類型,因此你可只通過(guò)聲明就可以創(chuàng)建一個(gè)全0的結(jié)構(gòu)體變量。

你也可以使用new創(chuàng)建一個(gè)結(jié)構(gòu)體。

復(fù)制代碼 代碼如下:

var p Point // 零值
pp := new(Point) // 慣用法

結(jié)構(gòu)體字面值語(yǔ)法也不出所料:

復(fù)制代碼 代碼如下:

p = Point{7.2, 8.4}
p = Point{y:8.4, x:7.2}
pp = Point{7.2, 8.4} // 慣用法
pp = Point{} //也是慣用法,== new(Point)

和數(shù)組一樣,得到了結(jié)構(gòu)體字面值的地址,就得到了新建結(jié)構(gòu)體的地址。

這些例子都是構(gòu)造器。

導(dǎo)出類型和字段

只有當(dāng)結(jié)構(gòu)體的字段(和方法,即將講解)名字的首字母大寫(xiě)時(shí),它才能被包外可見(jiàn)。

私有類型和字段:

復(fù)制代碼 代碼如下:

type point struct { x, y float64 }

導(dǎo)出類型和字段:
復(fù)制代碼 代碼如下:

type Point struct { X, Y float64 }

導(dǎo)出類型和私有類型混合字段:
復(fù)制代碼 代碼如下:

type Point struct {
X, Y float64 // exported
name string // not exported
}

你甚至可以創(chuàng)建一個(gè)帶有導(dǎo)出字段的私有類型。(練習(xí):何時(shí)能派上用場(chǎng)呢?)

匿名字段

在一個(gè)結(jié)構(gòu)體內(nèi),你可以聲明不帶名字的字段,比如另外一個(gè)結(jié)構(gòu)體類型。這些字段被稱為匿名字段。它們看起來(lái)就像里層的結(jié)構(gòu)體簡(jiǎn)單插入或“嵌入”到

外層結(jié)構(gòu)體似的。

這個(gè)簡(jiǎn)單的機(jī)制為從其他類型繼承已有的實(shí)現(xiàn)提供了一種方法。

下面是一個(gè)例子。

一個(gè)匿名結(jié)構(gòu)體字段:

復(fù)制代碼 代碼如下:

type A struct {
ax, ay int
}

type B struct {
A
bx, by float64
}

B看起來(lái)像有四個(gè)字段ax、ay、bx和by。B可看成{ax, ay int; bx, by float64}。

然后B的字面值必須提供細(xì)節(jié):

復(fù)制代碼 代碼如下:

b := B{A{1, 2}, 3.0, 4.0}
fmt.Println(b.ax, b.ay, b.bx, b.by)

輸出1 2 3 4

匿名字段以類型作為名字

匿名字段不僅僅是簡(jiǎn)單插入這些字段這么簡(jiǎn)單,其含義更為豐富:B還擁有字段A。匿名字段看起來(lái)就像名字為其類型名的字段。

復(fù)制代碼 代碼如下:

b := B{A{ 1, 2}, 3.0, 4.0}
fmt.Println(b.A)

輸出:{1 2}。如果A來(lái)自于另外一個(gè)包,這個(gè)字段依舊被稱為A。

復(fù)制代碼 代碼如下:

import "pkg"
type C struct { pkg.A }

c := C {pkg.A{1, 2}}
fmt.Println(c.A) // 不是 c.pkg.A

任意類型的匿名字段

任何具名類型或指向具名類型的指針都可以用作匿名字段。它們可以出現(xiàn)在結(jié)構(gòu)體中的任意位置。

復(fù)制代碼 代碼如下:

type C struct {
x float64
int
string
}
c := C{3.5, 7, "hello"}
fmt.Println(c.x, c.int, c.string)

輸出:3.5 7 hello

沖突和遮蔽

如果有兩個(gè)字段具有相同的名字(可能是一個(gè)繼承類型的名字),代碼將遵循下面規(guī)則:

1) 外層的名字遮蔽內(nèi)層的名字。這提供了一個(gè)重寫(xiě)字段/方法的方式。
2) 如果在同一層次上出現(xiàn)了相同的名字,如果名字被使用,那么將是一個(gè)錯(cuò)誤。(如果沒(méi)有使用,不會(huì)出現(xiàn)錯(cuò)誤)

二義性是沒(méi)有規(guī)則能解決的,必須被修正。

沖突的例子

復(fù)制代碼 代碼如下:

type A struct { a int }
type B struct { a, b int }
type C struct { A; B }
var c C

使用c.a將會(huì)出現(xiàn)錯(cuò)誤。它到底是c.A.a還是c.B.a呢?

復(fù)制代碼 代碼如下:

type D struct { B; b float64 }
var d D

使用d.b沒(méi)有問(wèn)題:它是float64類型變量,不是d.B.b。要獲得內(nèi)層的b,可用d.B.b。

您可能感興趣的文章:
  • GO語(yǔ)言基本類型分析
  • GO語(yǔ)言類型轉(zhuǎn)換和類型斷言實(shí)例分析
  • Go語(yǔ)言基礎(chǔ)知識(shí)總結(jié)(語(yǔ)法、變量、數(shù)值類型、表達(dá)式、控制結(jié)構(gòu)等)
  • GO語(yǔ)言基本數(shù)據(jù)類型總結(jié)
  • Go語(yǔ)言的方法接受者類型用值類型還是指針類型?
  • 為什么Go語(yǔ)言把類型聲明放在后面?
  • Go語(yǔ)言基本的語(yǔ)法和內(nèi)置數(shù)據(jù)類型初探
  • Go語(yǔ)言中如何通過(guò)方法為類型添加行為

標(biāo)簽:喀什 九江 湘潭 楚雄 晉城 本溪 運(yùn)城 深圳

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Go語(yǔ)言中的復(fù)合類型詳細(xì)介紹》,本文關(guān)鍵詞  語(yǔ)言,中的,復(fù)合,類型,詳細(xì),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Go語(yǔ)言中的復(fù)合類型詳細(xì)介紹》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于Go語(yǔ)言中的復(fù)合類型詳細(xì)介紹的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    义乌市| 杭州市| 夏津县| 渭南市| 定西市| 沾益县| 开阳县| 龙海市| 星座| 邹平县| 九龙城区| 肥西县| 潜江市| 八宿县| 修水县| 江油市| 来凤县| 古交市| 昆明市| 西宁市| 乌拉特中旗| 阿拉尔市| 马关县| 特克斯县| 柘城县| 合江县| 中西区| 白河县| 托克逊县| 泸溪县| 确山县| 新乐市| 自贡市| 济南市| 弥勒县| 阿勒泰市| 五大连池市| 丹巴县| 合水县| 怀来县| 滦平县|