真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

go語言冒號(hào)等號(hào) golang 冒號(hào)

沒有類,C語言有結(jié)構(gòu)體,那么Go的結(jié)構(gòu)體有什么特別之處?

Go語言中沒有“類”的概念,也不支持“類”的繼承等面向?qū)ο蟮母拍?。Go語言中通過結(jié)構(gòu)體的內(nèi)嵌再配合接口比面向?qū)ο缶哂懈叩臄U(kuò)展性和靈活性。

目前創(chuàng)新互聯(lián)公司已為上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、沭陽網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

自定義類型

在Go語言中有一些基本的數(shù)據(jù)類型,如string、整型、浮點(diǎn)型、布爾等數(shù)據(jù)類型, Go語言中可以使用type關(guān)鍵字來定義自定義類型。

自定義類型是定義了一個(gè)全新的類型。我們可以基于內(nèi)置的基本類型定義,也可以通過struct定義。例如:

通過Type關(guān)鍵字的定義,MyInt就是一種新的類型,它具有int的特性。

類型別名

類型別名是Go1.9版本添加的新功能。

類型別名規(guī)定:TypeAlias只是Type的別名,本質(zhì)上TypeAlias與Type是同一個(gè)類型。就像一個(gè)孩子小時(shí)候有小名、乳名,上學(xué)后用學(xué)名,英語老師又會(huì)給他起英文名,但這些名字都指的是他本人。

type TypeAlias = Type

我們之前見過的rune和byte就是類型別名,他們的定義如下:

類型定義和類型別名的區(qū)別

類型別名與類型定義表面上看只有一個(gè)等號(hào)的差異,我們通過下面的這段代碼來理解它們之間的區(qū)別。

結(jié)果顯示a的類型是main.NewInt,表示main包下定義的NewInt類型。b的類型是int。MyInt類型只會(huì)在代碼中存在,編譯完成時(shí)并不會(huì)有MyInt類型。

Go語言中的基礎(chǔ)數(shù)據(jù)類型可以表示一些事物的基本屬性,但是當(dāng)我們想表達(dá)一個(gè)事物的全部或部分屬性時(shí),這時(shí)候再用單一的基本數(shù)據(jù)類型明顯就無法滿足需求了,Go語言提供了一種自定義數(shù)據(jù)類型,可以封裝多個(gè)基本數(shù)據(jù)類型,這種數(shù)據(jù)類型叫結(jié)構(gòu)體,英文名稱struct。 也就是我們可以通過struct來定義自己的類型了。

Go語言中通過struct來實(shí)現(xiàn)面向?qū)ο蟆?/p>

結(jié)構(gòu)體的定義

使用type和struct關(guān)鍵字來定義結(jié)構(gòu)體,具體代碼格式如下:

其中:

舉個(gè)例子,我們定義一個(gè)Person(人)結(jié)構(gòu)體,代碼如下:

同樣類型的字段也可以寫在一行,

這樣我們就擁有了一個(gè)person的自定義類型,它有name、city、age三個(gè)字段,分別表示姓名、城市和年齡。這樣我們使用這個(gè)person結(jié)構(gòu)體就能夠很方便的在程序中表示和存儲(chǔ)人信息了。

語言內(nèi)置的基礎(chǔ)數(shù)據(jù)類型是用來描述一個(gè)值的,而結(jié)構(gòu)體是用來描述一組值的。比如一個(gè)人有名字、年齡和居住城市等,本質(zhì)上是一種聚合型的數(shù)據(jù)類型

結(jié)構(gòu)體實(shí)例化

只有當(dāng)結(jié)構(gòu)體實(shí)例化時(shí),才會(huì)真正地分配內(nèi)存。也就是必須實(shí)例化后才能使用結(jié)構(gòu)體的字段。

基本實(shí)例化

舉個(gè)例子:

我們通過.來訪問結(jié)構(gòu)體的字段(成員變量),例如p1.name和p1.age等。

匿名結(jié)構(gòu)體

在定義一些臨時(shí)數(shù)據(jù)結(jié)構(gòu)等場景下還可以使用匿名結(jié)構(gòu)體。

創(chuàng)建指針類型結(jié)構(gòu)體

我們還可以通過使用new關(guān)鍵字對結(jié)構(gòu)體進(jìn)行實(shí)例化,得到的是結(jié)構(gòu)體的地址。 格式如下:

從打印的結(jié)果中我們可以看出p2是一個(gè)結(jié)構(gòu)體指針。

需要注意的是在Go語言中支持對結(jié)構(gòu)體指針直接使用.來訪問結(jié)構(gòu)體的成員。

取結(jié)構(gòu)體的地址實(shí)例化

使用對結(jié)構(gòu)體進(jìn)行取地址操作相當(dāng)于對該結(jié)構(gòu)體類型進(jìn)行了一次new實(shí)例化操作。

p3.name = "七米"其實(shí)在底層是(*p3).name = "七米",這是Go語言幫我們實(shí)現(xiàn)的語法糖。

結(jié)構(gòu)體初始化

沒有初始化的結(jié)構(gòu)體,其成員變量都是對應(yīng)其類型的零值。

使用鍵值對初始化

使用鍵值對對結(jié)構(gòu)體進(jìn)行初始化時(shí),鍵對應(yīng)結(jié)構(gòu)體的字段,值對應(yīng)該字段的初始值。

也可以對結(jié)構(gòu)體指針進(jìn)行鍵值對初始化,例如:

當(dāng)某些字段沒有初始值的時(shí)候,該字段可以不寫。此時(shí),沒有指定初始值的字段的值就是該字段類型的零值。

使用值的列表初始化

初始化結(jié)構(gòu)體的時(shí)候可以簡寫,也就是初始化的時(shí)候不寫鍵,直接寫值:

使用這種格式初始化時(shí),需要注意:

結(jié)構(gòu)體內(nèi)存布局

結(jié)構(gòu)體占用一塊連續(xù)的內(nèi)存。

輸出:

【進(jìn)階知識(shí)點(diǎn)】關(guān)于Go語言中的內(nèi)存對齊推薦閱讀:在 Go 中恰到好處的內(nèi)存對齊

面試題

請問下面代碼的執(zhí)行結(jié)果是什么?

構(gòu)造函數(shù)

Go語言的結(jié)構(gòu)體沒有構(gòu)造函數(shù),我們可以自己實(shí)現(xiàn)。 例如,下方的代碼就實(shí)現(xiàn)了一個(gè)person的構(gòu)造函數(shù)。 因?yàn)閟truct是值類型,如果結(jié)構(gòu)體比較復(fù)雜的話,值拷貝性能開銷會(huì)比較大,所以該構(gòu)造函數(shù)返回的是結(jié)構(gòu)體指針類型。

調(diào)用構(gòu)造函數(shù)

方法和接收者

Go語言中的方法(Method)是一種作用于特定類型變量的函數(shù)。這種特定類型變量叫做接收者(Receiver)。接收者的概念就類似于其他語言中的this或者 self。

方法的定義格式如下:

其中,

舉個(gè)例子:

方法與函數(shù)的區(qū)別是,函數(shù)不屬于任何類型,方法屬于特定的類型。

指針類型的接收者

指針類型的接收者由一個(gè)結(jié)構(gòu)體的指針組成,由于指針的特性,調(diào)用方法時(shí)修改接收者指針的任意成員變量,在方法結(jié)束后,修改都是有效的。這種方式就十分接近于其他語言中面向?qū)ο笾械膖his或者self。 例如我們?yōu)镻erson添加一個(gè)SetAge方法,來修改實(shí)例變量的年齡。

調(diào)用該方法:

值類型的接收者

當(dāng)方法作用于值類型接收者時(shí),Go語言會(huì)在代碼運(yùn)行時(shí)將接收者的值復(fù)制一份。在值類型接收者的方法中可以獲取接收者的成員值,但修改操作只是針對副本,無法修改接收者變量本身。

什么時(shí)候應(yīng)該使用指針類型接收者

任意類型添加方法

在Go語言中,接收者的類型可以是任何類型,不僅僅是結(jié)構(gòu)體,任何類型都可以擁有方法。 舉個(gè)例子,我們基于內(nèi)置的int類型使用type關(guān)鍵字可以定義新的自定義類型,然后為我們的自定義類型添加方法。

注意事項(xiàng): 非本地類型不能定義方法,也就是說我們不能給別的包的類型定義方法。

結(jié)構(gòu)體的匿名字段

匿名字段默認(rèn)采用類型名作為字段名,結(jié)構(gòu)體要求字段名稱必須唯一,因此一個(gè)結(jié)構(gòu)體中同種類型的匿名字段只能有一個(gè)。

嵌套結(jié)構(gòu)體

一個(gè)結(jié)構(gòu)體中可以嵌套包含另一個(gè)結(jié)構(gòu)體或結(jié)構(gòu)體指針。

嵌套匿名結(jié)構(gòu)體

當(dāng)訪問結(jié)構(gòu)體成員時(shí)會(huì)先在結(jié)構(gòu)體中查找該字段,找不到再去匿名結(jié)構(gòu)體中查找。

嵌套結(jié)構(gòu)體的字段名沖突

嵌套結(jié)構(gòu)體內(nèi)部可能存在相同的字段名。這個(gè)時(shí)候?yàn)榱吮苊馄缌x需要指定具體的內(nèi)嵌結(jié)構(gòu)體的字段。

結(jié)構(gòu)體的“繼承”

Go語言中使用結(jié)構(gòu)體也可以實(shí)現(xiàn)其他編程語言中面向?qū)ο蟮睦^承。

結(jié)構(gòu)體字段的可見性

結(jié)構(gòu)體中字段大寫開頭表示可公開訪問,小寫表示私有(僅在定義當(dāng)前結(jié)構(gòu)體的包中可訪問)。

結(jié)構(gòu)體與JSON序列化

JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式。易于人閱讀和編寫。同時(shí)也易于機(jī)器解析和生成。JSON鍵值對是用來保存JS對象的一種方式,鍵/值對組合中的鍵名寫在前面并用雙引號(hào)""包裹,使用冒號(hào):分隔,然后緊接著值;多個(gè)鍵值之間使用英文,分隔。

結(jié)構(gòu)體標(biāo)簽(Tag)

Tag是結(jié)構(gòu)體的元信息,可以在運(yùn)行的時(shí)候通過反射的機(jī)制讀取出來。 Tag在結(jié)構(gòu)體字段的后方定義,由一對反引號(hào)包裹起來,具體的格式如下:

`key1:"value1" key2:"value2"`

結(jié)構(gòu)體標(biāo)簽由一個(gè)或多個(gè)鍵值對組成。鍵與值使用冒號(hào)分隔,值用雙引號(hào)括起來。鍵值對之間使用一個(gè)空格分隔。 注意事項(xiàng): 為結(jié)構(gòu)體編寫Tag時(shí),必須嚴(yán)格遵守鍵值對的規(guī)則。結(jié)構(gòu)體標(biāo)簽的解析代碼的容錯(cuò)能力很差,一旦格式寫錯(cuò),編譯和運(yùn)行時(shí)都不會(huì)提示任何錯(cuò)誤,通過反射也無法正確取值。例如不要在key和value之間添加空格。

例如我們?yōu)镾tudent結(jié)構(gòu)體的每個(gè)字段定義json序列化時(shí)使用的Tag:

Go語言和其他語言的不同之基本語法

Go語言作為出現(xiàn)比較晚的一門編程語言,在其原生支持高并發(fā)、云原生等領(lǐng)域的優(yōu)秀表現(xiàn),像目前比較流行的容器編排技術(shù)Kubernetes、容器技術(shù)Docker都是用Go語言寫的,像Java等其他面向?qū)ο蟮恼Z言,雖然也能做云原生相關(guān)的開發(fā),但是支持的程度遠(yuǎn)沒有Go語言高,憑借其語言特性和簡單的編程方式,彌補(bǔ)了其他編程語言一定程度上的不足,一度成為一個(gè)熱門的編程語言。

最近在學(xué)習(xí)Go語言,我之前使用過C#、Java等面向?qū)ο缶幊痰恼Z言,發(fā)現(xiàn)其中有很多的編程方式和其他語言有區(qū)別的地方,好記性不如爛筆頭,總結(jié)一下,和其他語言做個(gè)對比。這里只總結(jié)差異的地方,具體的語法不做詳細(xì)的介紹。

種一棵樹最好的時(shí)間是十年前,其次是現(xiàn)在。

3)變量初始化時(shí)候可以和其他語言一樣直接在變量后面加等號(hào),等號(hào)后面為要初始化的值,也可以使用變量名:=變量值的簡單方式

3)變量賦值 Go語言的變量賦值和多數(shù)語言一致,但是Go語言提供了多重賦值的功能,比如下面這個(gè)交換i、j變量的語句:

在不支持多重賦值的語言中,交換兩個(gè)變量的值需要引入一個(gè)中間變量:

4)匿名變量

在使用其他語言時(shí),有時(shí)候要獲取一個(gè)值,卻因?yàn)樵摵瘮?shù)返回多個(gè)值而不得不定義很多沒有的變量,Go語言可以借助多重返回值和匿名變量來避免這種寫法,使代碼看起來更優(yōu)雅。

假如GetName()函數(shù)返回3個(gè)值,分別是firstName,lastName和nickName

若指向獲得nickName,則函數(shù)調(diào)用可以這樣寫

這種寫法可以讓代碼更清晰,從而大幅降低溝通的復(fù)雜度和維護(hù)的難度。

1)基本常量

常量使用關(guān)鍵字const 定義,可以限定常量類型,但不是必須的,如果沒有定義常量的類型,是無類型常量

2)預(yù)定義常量

Go語言預(yù)定義了這些常量 true、false和iota

iota比較特殊,可以被任務(wù)是一個(gè)可被編譯器修改的常量,在每個(gè)const關(guān)鍵字出現(xiàn)時(shí)被重置為0,然后在下一個(gè)const出現(xiàn)之前每出現(xiàn)一個(gè)iota,其所代表的數(shù)字會(huì)自動(dòng)加1.

3)枚舉

1)int 和int32在Go語言中被認(rèn)為是兩種不同類型的類型

2)Go語言定義了兩個(gè)浮點(diǎn)型float32和float64,其中前者等價(jià)于C語言的float類型,后者等價(jià)于C語言的double類型

3)go語言支持復(fù)數(shù)類型

復(fù)數(shù)實(shí)際上是由兩個(gè)實(shí)數(shù)(在計(jì)算機(jī)中使用浮點(diǎn)數(shù)表示)構(gòu)成,一個(gè)表示實(shí)部(real)、一個(gè)表示虛部(imag)。也就是數(shù)學(xué)上的那個(gè)復(fù)數(shù)

復(fù)數(shù)的表示

實(shí)部與虛部

對于一個(gè)復(fù)數(shù)z=complex(x,y),就可以通過Go語言內(nèi)置函數(shù)real(z)獲得該復(fù)數(shù)的實(shí)部,也就是x,通過imag(z)獲得該復(fù)數(shù)的虛部,也就是y

4)數(shù)組(值類型,長度在定義后無法再次修改,每次傳遞都將產(chǎn)生一個(gè)副本。)

5)數(shù)組切片(slice)

數(shù)組切片(slice)彌補(bǔ)了數(shù)組的不足,其數(shù)據(jù)結(jié)構(gòu)可以抽象為以下三個(gè)變量:

6)Map 在go語言中Map不需要引入任何庫,使用很方便

Go循環(huán)語句只支持for關(guān)鍵字,不支持while和do-while

goto語句的語義非常簡單,就是跳轉(zhuǎn)到本函數(shù)內(nèi)的某個(gè)標(biāo)簽

今天就介紹到這里,以后我會(huì)在總結(jié)Go語言在其他方面比如并發(fā)編程、面向?qū)ο?、網(wǎng)絡(luò)編程等方面的不同及使用方法。希望對大家有所幫助。

Go 語言內(nèi)存管理(三):逃逸分析

Go 語言較之 C 語言一個(gè)很大的優(yōu)勢就是自帶 GC 功能,可 GC 并不是沒有代價(jià)的。寫 C 語言的時(shí)候,在一個(gè)函數(shù)內(nèi)聲明的變量,在函數(shù)退出后會(huì)自動(dòng)釋放掉,因?yàn)檫@些變量分配在棧上。如果你期望變量的數(shù)據(jù)可以在函數(shù)退出后仍然能被訪問,就需要調(diào)用 malloc 方法在堆上申請內(nèi)存,如果程序不再需要這塊內(nèi)存了,再調(diào)用 free 方法釋放掉。Go 語言不需要你主動(dòng)調(diào)用 malloc 來分配堆空間,編譯器會(huì)自動(dòng)分析,找出需要 malloc 的變量,使用堆內(nèi)存。編譯器的這個(gè)分析過程就叫做逃逸分析。

所以你在一個(gè)函數(shù)中通過 dict := make(map[string]int) 創(chuàng)建一個(gè) map 變量,其背后的數(shù)據(jù)是放在??臻g上還是堆空間上,是不一定的。這要看編譯器分析的結(jié)果。

可逃逸分析并不是百分百準(zhǔn)確的,它有缺陷。有的時(shí)候你會(huì)發(fā)現(xiàn)有些變量其實(shí)在??臻g上分配完全沒問題的,但編譯后程序還是把這些數(shù)據(jù)放在了堆上。如果你了解 Go 語言編譯器逃逸分析的機(jī)制,在寫代碼的時(shí)候就可以有意識(shí)地繞開這些缺陷,使你的程序更高效。

Go 語言雖然在內(nèi)存管理方面降低了編程門檻,即使你不了解堆棧也能正常開發(fā),但如果你要在性能上較真的話,還是要掌握這些基礎(chǔ)知識(shí)。

這里不對堆內(nèi)存和棧內(nèi)存的區(qū)別做太多闡述。簡單來說就是, 棧分配廉價(jià),堆分配昂貴。 ??臻g會(huì)隨著一個(gè)函數(shù)的結(jié)束自動(dòng)釋放,堆空間需要時(shí)間 GC 模塊不斷地跟蹤掃描回收。如果對這兩個(gè)概念有些迷糊,建議閱讀下面 2 個(gè)文章:

這里舉一個(gè)小例子,來對比下堆棧的差別:

stack 函數(shù)中的變量 i 在函數(shù)退出會(huì)自動(dòng)釋放;而 heap 函數(shù)返回的是對變量 i 的引用,也就是說 heap() 退出后,表示變量 i 還要能被訪問,它會(huì)自動(dòng)被分配到堆空間上。

他們編譯出來的代碼如下:

邏輯的復(fù)雜度不言而喻,從上面的匯編中可看到, heap() 函數(shù)調(diào)用了 runtime.newobject() 方法,它會(huì)調(diào)用 mallocgc 方法從 mcache 上申請內(nèi)存,申請的內(nèi)部邏輯前面文章已經(jīng)講述過。堆內(nèi)存分配不僅分配上邏輯比??臻g分配復(fù)雜,它最致命的是會(huì)帶來很大的管理成本,Go 語言要消耗很多的計(jì)算資源對其進(jìn)行標(biāo)記回收(也就是 GC 成本)。

Go 編輯器會(huì)自動(dòng)幫我們找出需要進(jìn)行動(dòng)態(tài)分配的變量,它是在編譯時(shí)追蹤一個(gè)變量的生命周期,如果能確認(rèn)一個(gè)數(shù)據(jù)只在函數(shù)空間內(nèi)訪問,不會(huì)被外部使用,則使用??臻g,否則就要使用堆空間。

我們在 go build 編譯代碼時(shí),可使用 -gcflags '-m' 參數(shù)來查看逃逸分析日志。

以上面的兩個(gè)函數(shù)為例,編譯的日志輸出是:

日志中的 i escapes to heap 表示該變量數(shù)據(jù)逃逸到了堆上。

需要使用堆空間,所以逃逸,這沒什么可爭議的。但編譯器有時(shí)會(huì)將 不需要 使用堆空間的變量,也逃逸掉。這里是容易出現(xiàn)性能問題的大坑。網(wǎng)上有很多相關(guān)文章,列舉了一些導(dǎo)致逃逸情況,其實(shí)總結(jié)起來就一句話:

多級(jí)間接賦值容易導(dǎo)致逃逸 。

這里的多級(jí)間接指的是,對某個(gè)引用類對象中的引用類成員進(jìn)行賦值。Go 語言中的引用類數(shù)據(jù)類型有 func , interface , slice , map , chan , *Type(指針) 。

記住公式 Data.Field = Value ,如果 Data , Field 都是引用類的數(shù)據(jù)類型,則會(huì)導(dǎo)致 Value 逃逸。這里的等號(hào) = 不單單只賦值,也表示參數(shù)傳遞。

根據(jù)公式,我們假設(shè)一個(gè)變量 data 是以下幾種類型,相應(yīng)的可以得出結(jié)論:

下面給出一些實(shí)際的例子:

如果變量值是一個(gè)函數(shù),函數(shù)的參數(shù)又是引用類型,則傳遞給它的參數(shù)都會(huì)逃逸。

上例中 te 的類型是 func(*int) ,屬于引用類型,參數(shù) *int 也是引用類型,則調(diào)用 te(j) 形成了為 te 的參數(shù)(成員) *int 賦值的現(xiàn)象,即 te.i = j 會(huì)導(dǎo)致逃逸。代碼中其他幾種調(diào)用都沒有形成 多級(jí)間接賦值 情況。

同理,如果函數(shù)的參數(shù)類型是 slice , map 或 interface{} 都會(huì)導(dǎo)致參數(shù)逃逸。

匿名函數(shù)的調(diào)用也是一樣的,它本質(zhì)上也是一個(gè)函數(shù)變量。有興趣的可以自己測試一下。

只要使用了 Interface 類型(不是 interafce{} ),那么賦值給它的變量一定會(huì)逃逸。因?yàn)? interfaceVariable.Method() 先是間接的定位到它的實(shí)際值,再調(diào)用實(shí)際值的同名方法,執(zhí)行時(shí)實(shí)際值作為參數(shù)傳遞給方法。相當(dāng)于 interfaceVariable.Method.this = realValue

向 channel 中發(fā)送數(shù)據(jù),本質(zhì)上就是為 channel 內(nèi)部的成員賦值,就像給一個(gè) slice 中的某一項(xiàng)賦值一樣。所以 chan *Type , chan map[Type]Type , chan []Type , chan interface{} 類型都會(huì)導(dǎo)致發(fā)送到 channel 中的數(shù)據(jù)逃逸。

這本來也是情理之中的,發(fā)送給 channel 的數(shù)據(jù)是要與其他函數(shù)分享的,為了保證發(fā)送過去的指針依然可用,只能使用堆分配。

可變參數(shù)如 func(arg ...string) 實(shí)際與 func(arg []string) 是一樣的,會(huì)增加一層訪問路徑。這也是 fmt.Sprintf 總是會(huì)使參數(shù)逃逸的原因。

例子非常多,這里不能一一列舉,我們只需要記住分析方法就好,即,2 級(jí)或更多級(jí)的訪問賦值會(huì) 容易 導(dǎo)致數(shù)據(jù)逃逸。這里加上 容易 二字是因?yàn)殡S著語言的發(fā)展,相信這些問題會(huì)被慢慢解決,但現(xiàn)階段,這個(gè)可以作為我們分析逃逸現(xiàn)象的依據(jù)。

下面代碼中包含 2 種很常規(guī)的寫法,但他們卻有著很大的性能差距,建議自己想下為什么。

Benchmark 和 pprof 給出的結(jié)果:

熟悉堆棧概念可以讓我們更容易看透 Go 程序的性能問題,并進(jìn)行優(yōu)化。

多級(jí)間接賦值會(huì)導(dǎo)致 Go 編譯器出現(xiàn)不必要的逃逸,在一些情況下可能我們只需要修改一下數(shù)據(jù)結(jié)構(gòu)就會(huì)使性能有大幅提升。這也是很多人不推薦在 Go 中使用指針的原因,因?yàn)樗鼤?huì)增加一級(jí)訪問路徑,而 map , slice , interface{} 等類型是不可避免要用到的,為了減少不必要的逃逸,只能拿指針開刀了。

大多數(shù)情況下,性能優(yōu)化都會(huì)為程序帶來一定的復(fù)雜度。建議實(shí)際項(xiàng)目中還是怎么方便怎么寫,功能完成后通過性能分析找到瓶頸所在,再對局部進(jìn)行優(yōu)化。

GO語言(十三):使用 Go 和 Gin 開發(fā) RESTful API(下)

當(dāng)客戶端在 發(fā)出POST請求時(shí)/albums,您希望將請求正文中描述的專輯添加到現(xiàn)有專輯數(shù)據(jù)中。

為此,您將編寫以下內(nèi)容:

1、編寫代碼

a.添加代碼以將專輯數(shù)據(jù)添加到專輯列表。

在此代碼中:

1)用于Context.BindJSON 將請求正文綁定到newAlbum。

2) album將從 JSON 初始化的結(jié)構(gòu)附加到albums 切片。

3)向響應(yīng)添加201狀態(tài)代碼,以及表示您添加的專輯的 JSON。

b.更改您的main函數(shù),使其包含該router.POST函數(shù),如下所示。

在此代碼中:

1)將路徑中的POST方法與 /albumspostAlbums函數(shù)相關(guān)聯(lián)。

使用 Gin,您可以將處理程序與 HTTP 方法和路徑組合相關(guān)聯(lián)。這樣,您可以根據(jù)客戶端使用的方法將發(fā)送到單個(gè)路徑的請求單獨(dú)路由。

a.如果服務(wù)器從上一節(jié)開始仍在運(yùn)行,請停止它。

b.從包含 main.go 的目錄中的命令行,運(yùn)行代碼。

c.從不同的命令行窗口,用于curl向正在運(yùn)行的 Web 服務(wù)發(fā)出請求。

該命令應(yīng)顯示添加專輯的標(biāo)題和 JSON。

d.與上一節(jié)一樣,使用curl檢索完整的專輯列表,您可以使用它來確認(rèn)添加了新專輯。

該命令應(yīng)顯示專輯列表。

當(dāng)客戶端向 發(fā)出請求時(shí)GET /albums/[id],您希望返回 ID 與id路徑參數(shù)匹配的專輯。

為此,您將:

a.在您在上一節(jié)中添加的函數(shù)下方postAlbums,粘貼以下代碼以檢索特定專輯。

此getAlbumByID函數(shù)將提取請求路徑中的 ID,然后找到匹配的專輯。

在此代碼中:

(1)Context.Param用于從 URL 中檢索id路徑參數(shù)。當(dāng)您將此處理程序映射到路徑時(shí),您將在路徑中包含參數(shù)的占位符。

(2)循環(huán)album切片中的結(jié)構(gòu),尋找其ID 字段值與id參數(shù)值匹配的結(jié)構(gòu)。如果找到,則將該album結(jié)構(gòu)序列化為 JSON,并將其作為帶有200 OK HTTP 代碼的響應(yīng)返回。

如上所述,實(shí)際使用中的服務(wù)可能會(huì)使用數(shù)據(jù)庫查詢來執(zhí)行此查找。

(3)如果找不到專輯,則返回 HTTP 404錯(cuò)誤。

b.最后,更改您的main,使其包含對router.GET的新調(diào)用,路徑現(xiàn)在為/albums/:id ,如以下示例所示。

在此代碼中:

(1)將/albums/:id路徑與getAlbumByID功能相關(guān)聯(lián)。在 Gin 中,路徑中項(xiàng)目前面的冒號(hào)表示該項(xiàng)目是路徑參數(shù)。

a.如果服務(wù)器從上一節(jié)開始仍在運(yùn)行,請停止它。

b.在包含 main.go 的目錄中的命令行中,運(yùn)行代碼以啟動(dòng)服務(wù)器。

c.從不同的命令行窗口,用于curl向正在運(yùn)行的 Web 服務(wù)發(fā)出請求。

該命令應(yīng)顯示您使用其 ID 的專輯的 JSON。如果找不到專輯,您將收到帶有錯(cuò)誤消息的 JSON。

恭喜!您剛剛使用 Go 和 Gin 編寫了一個(gè)簡單的 RESTful Web 服務(wù)。

本節(jié)包含您使用本教程構(gòu)建的應(yīng)用程序的代碼。

寫命令行應(yīng)用程序什么不可或缺?Go可以這樣處理命令行參數(shù)

Go語言內(nèi)置的flag包實(shí)現(xiàn)了命令行參數(shù)的解析,flag包使得開發(fā)命令行工具更為簡單。

如果你只是簡單的想要獲取命令行參數(shù),可以像下面的代碼示例一樣使用os.Args來獲取命令行參數(shù)。

將上面的代碼執(zhí)行g(shù)o build -o "args_demo"編譯之后,執(zhí)行:

os.Args是一個(gè)存儲(chǔ)命令行參數(shù)的字符串切片,它的第一個(gè)元素是執(zhí)行文件的名稱。

本文介紹了flag包的常用函數(shù)和基本用法,更詳細(xì)的內(nèi)容請查看官方文檔。

flag包支持的命令行參數(shù)類型有bool、int、int64、uint、uint64、float float64、string、duration。

有以下兩種常用的定義命令行flag參數(shù)的方法。

基本格式如下:

flag.Type(flag名, 默認(rèn)值, 幫助信息)*Type 例如我們要定義姓名、年齡、婚否三個(gè)命令行參數(shù),我們可以按如下方式定義:

需要注意的是,此時(shí)name、age、married、delay均為對應(yīng)類型的指針。

基本格式如下: flag.TypeVar(Type指針, flag名, 默認(rèn)值, 幫助信息) 例如我們要定義姓名、年齡、婚否三個(gè)命令行參數(shù),我們可以按如下方式定義:

通過以上兩種方法定義好命令行flag參數(shù)后,需要通過調(diào)用flag.Parse()來對命令行參數(shù)進(jìn)行解析。

支持的命令行參數(shù)格式有以下幾種:

其中,布爾類型的參數(shù)必須使用等號(hào)的方式指定。

Flag解析在第一個(gè)非flag參數(shù)(單個(gè)”-“不是flag參數(shù))之前停止,或者在終止符”–“之后停止。

定義

使用

命令行參數(shù)使用提示:

$ ./flag_demo -help

Usage of ./flag_demo:

-age int

年齡 (default 18)

-d duration

時(shí)間間隔

-married

婚否

-name string

姓名 (default "張三")

正常使用命令行flag參數(shù):

使用非flag命令行參數(shù):

原文鏈接:


文章名稱:go語言冒號(hào)等號(hào) golang 冒號(hào)
鏈接分享:http://weahome.cn/article/hjpici.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部