go語言內(nèi)存分布 go語言內(nèi)存占用

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

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

憑祥網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)成立與2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。

自定義類型

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

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

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

類型別名

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

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

type TypeAlias = Type

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

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

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

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

Go語言中的基礎(chǔ)數(shù)據(jù)類型可以表示一些事物的基本屬性,但是當(dāng)我們想表達(dá)一個事物的全部或部分屬性時,這時候再用單一的基本數(shù)據(jù)類型明顯就無法滿足需求了,Go語言提供了一種自定義數(shù)據(jù)類型,可以封裝多個基本數(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)體,具體代碼格式如下:

其中:

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

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

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

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

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

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

基本實(shí)例化

舉個例子:

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

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

在定義一些臨時數(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是一個結(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)行初始化時,鍵對應(yīng)結(jié)構(gòu)體的字段,值對應(yīng)該字段的初始值。

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

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

使用值的列表初始化

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

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

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

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

輸出:

【進(jìn)階知識點(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)了一個person的構(gòu)造函數(shù)。 因?yàn)閟truct是值類型,如果結(jié)構(gòu)體比較復(fù)雜的話,值拷貝性能開銷會比較大,所以該構(gòu)造函數(shù)返回的是結(jié)構(gòu)體指針類型。

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

方法和接收者

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

方法的定義格式如下:

其中,

舉個例子:

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

指針類型的接收者

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

調(diào)用該方法:

值類型的接收者

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

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

任意類型添加方法

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

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

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

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

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

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

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

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

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

嵌套結(jié)構(gòu)體內(nèi)部可能存在相同的字段名。這個時候?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) 是一種輕量級的數(shù)據(jù)交換格式。易于人閱讀和編寫。同時也易于機(jī)器解析和生成。JSON鍵值對是用來保存JS對象的一種方式,鍵/值對組合中的鍵名寫在前面并用雙引號""包裹,使用冒號:分隔,然后緊接著值;多個鍵值之間使用英文,分隔。

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

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

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

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

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

Go語言中恰到好處的內(nèi)存對齊

在開始之前,希望你計(jì)算一下 Part1 共占用的大小是多少呢?

輸出結(jié)果:

這么一算, Part1 這一個結(jié)構(gòu)體的占用內(nèi)存大小為 1+4+1+8+1 = 15 個字節(jié)。相信有的小伙伴是這么算的,看上去也沒什么毛病

真實(shí)情況是怎么樣的呢?我們實(shí)際調(diào)用看看,如下:

輸出結(jié)果:

最終輸出為占用 32 個字節(jié)。這與前面所預(yù)期的結(jié)果完全不一樣。這充分地說明了先前的計(jì)算方式是錯誤的。為什么呢?

在這里要提到 “內(nèi)存對齊” 這一概念,才能夠用正確的姿勢去計(jì)算,接下來我們詳細(xì)的講講它是什么

有的小伙伴可能會認(rèn)為內(nèi)存讀取,就是一個簡單的字節(jié)數(shù)組擺放

上圖表示一個坑一個蘿卜的內(nèi)存讀取方式。但實(shí)際上 CPU 并不會以一個一個字節(jié)去讀取和寫入內(nèi)存。相反 CPU 讀取內(nèi)存是 一塊一塊讀取 的,塊的大小可以為 2、4、6、8、16 字節(jié)等大小。塊大小我們稱其為 內(nèi)存訪問粒度 。如下圖:

在樣例中,假設(shè)訪問粒度為 4。 CPU 是以每 4 個字節(jié)大小的訪問粒度去讀取和寫入內(nèi)存的。這才是正確的姿勢

另外作為一個工程師,你也很有必要學(xué)習(xí)這塊知識點(diǎn)哦 :)

在上圖中,假設(shè)從 Index 1 開始讀取,將會出現(xiàn)很崩潰的問題。因?yàn)樗膬?nèi)存訪問邊界是不對齊的。因此 CPU 會做一些額外的處理工作。如下:

從上述流程可得出,不做 “內(nèi)存對齊” 是一件有點(diǎn) "麻煩" 的事。因?yàn)樗鼤黾釉S多耗費(fèi)時間的動作

而假設(shè)做了內(nèi)存對齊,從 Index 0 開始讀取 4 個字節(jié),只需要讀取一次,也不需要額外的運(yùn)算。這顯然高效很多,是標(biāo)準(zhǔn)的 空間換時間 做法

在不同平臺上的編譯器都有自己默認(rèn)的 “對齊系數(shù)”,可通過預(yù)編譯命令 #pragma pack(n) 進(jìn)行變更,n 就是代指 “對齊系數(shù)”。一般來講,我們常用的平臺的系數(shù)如下:

另外要注意,不同硬件平臺占用的大小和對齊值都可能是不一樣的。因此本文的值不是唯一的,調(diào)試的時候需按本機(jī)的實(shí)際情況考慮

輸出結(jié)果:

在 Go 中可以調(diào)用 unsafe.Alignof 來返回相應(yīng)類型的對齊系數(shù)。通過觀察輸出結(jié)果,可得知基本都是 2^n ,最大也不會超過 8。這是因?yàn)槲沂痔幔?4 位)編譯器默認(rèn)對齊系數(shù)是 8,因此最大值不會超過這個數(shù)

在上小節(jié)中,提到了結(jié)構(gòu)體中的成員變量要做字節(jié)對齊。那么想當(dāng)然身為最終結(jié)果的結(jié)構(gòu)體,也是需要做字節(jié)對齊的

接下來我們一起分析一下,“它” 到底經(jīng)歷了些什么,影響了 “預(yù)期” 結(jié)果

在每個成員變量進(jìn)行對齊后,根據(jù)規(guī)則 2,整個結(jié)構(gòu)體本身也要進(jìn)行字節(jié)對齊,因?yàn)榭砂l(fā)現(xiàn)它可能并不是 2^n ,不是偶數(shù)倍。顯然不符合對齊的規(guī)則

根據(jù)規(guī)則 2,可得出對齊值為 8。現(xiàn)在的偏移量為 25,不是 8 的整倍數(shù)。因此確定偏移量為 32。對結(jié)構(gòu)體進(jìn)行對齊

Part1 內(nèi)存布局:axxx|bbbb|cxxx|xxxx|dddd|dddd|exxx|xxxx

通過本節(jié)的分析,可得知先前的 “推算” 為什么錯誤?

是因?yàn)閷?shí)際內(nèi)存管理并非 “一個蘿卜一個坑” 的思想。而是一塊一塊。通過空間換時間(效率)的思想來完成這塊讀取、寫入。另外也需要兼顧不同平臺的內(nèi)存操作情況

在上一小節(jié),可得知根據(jù)成員變量的類型不同,其結(jié)構(gòu)體的內(nèi)存會產(chǎn)生對齊等動作。那假設(shè)字段順序不同,會不會有什么變化呢?我們一起來試試吧 :-)

輸出結(jié)果:

通過結(jié)果可以驚喜的發(fā)現(xiàn),只是 “簡單” 對成員變量的字段順序進(jìn)行改變,就改變了結(jié)構(gòu)體占用大小

接下來我們一起剖析一下 Part2 ,看看它的內(nèi)部到底和上一位之間有什么區(qū)別,才導(dǎo)致了這樣的結(jié)果?

符合規(guī)則 2,不需要額外對齊

Part2 內(nèi)存布局:ecax|bbbb|dddd|dddd

通過對比 Part1 和 Part2 的內(nèi)存布局,你會發(fā)現(xiàn)兩者有很大的不同。如下:

仔細(xì)一看, Part1 存在許多 Padding。顯然它占據(jù)了不少空間,那么 Padding 是怎么出現(xiàn)的呢?

通過本文的介紹,可得知是由于不同類型導(dǎo)致需要進(jìn)行字節(jié)對齊,以此保證內(nèi)存的訪問邊界

那么也不難理解,為什么 調(diào)整結(jié)構(gòu)體內(nèi)成員變量的字段順序 就能達(dá)到縮小結(jié)構(gòu)體占用大小的疑問了,是因?yàn)榍擅畹販p少了 Padding 的存在。讓它們更 “緊湊” 了。這一點(diǎn)對于加深 Go 的內(nèi)存布局印象和大對象的優(yōu)化非常有幫

如何在golang 中調(diào)用c的靜態(tài)庫或者動態(tài)庫

Cgo 使得Go程序能夠調(diào)用C代碼. cgo讀入一個用特別的格式寫的Go語言源文件, 輸出Go和C程序, 使得C程序能打包到Go語言的程序包中.

舉例說明一下. 下面是一個Go語言包, 包含了兩個函數(shù) -- Random 和 Seed -- 是C語言庫中random和srandom函數(shù)的馬甲.

package rand

/*

#include stdlib.h

*/ import "C" func Random() int { return int(C.random()) } func Seed(i int) { C.srandom(C.uint(i)) }

我們來看一下這里都有什么內(nèi)容. 開始是一個包的導(dǎo)入語句.

rand包導(dǎo)入了"C"包, 但你會發(fā)現(xiàn)在Go的標(biāo)準(zhǔn)庫里沒有這個包. 那是因?yàn)镃是一個"偽包", 一個為cgo引入的特殊的包名, 它是C命名空間的一個引用.

rand 包包含4個到C包的引用: 調(diào)用 C.random和C.srandom, 類型轉(zhuǎn)換 C.uint(i)還有引用語句.

Random函數(shù)調(diào)用libc中的random函數(shù), 然后回返結(jié)果. 在C中, random返回一個C類型的長整形值, cgo把它輪換為C.long. 這個值必需轉(zhuǎn)換成Go的類型, 才能在Go程序中使用. 使用一個常見的Go類型轉(zhuǎn)換:

func Random() int { return int(C.random()) }

這是一個等價的函數(shù), 使用了一個臨時變量來進(jìn)行類型轉(zhuǎn)換:

func Random() int { var r C.long = C.random() return int(r) }

Seed函數(shù)則相反. 它接受一個Go語言的int類型, 轉(zhuǎn)換成C語言的unsigned int類型, 然后傳遞給C的srandom函數(shù).

func Seed(i int) { C.srandom(C.uint(i)) }

需要注意的是, cgo中的unsigned int類型寫為C.uint; cgo的文檔中有完整的類型列表.

這個例子中還有一個細(xì)節(jié)我們沒有說到, 那就是導(dǎo)入語句上面的注釋.

/*

#include stdlib.h

*/ import "C"

Cgo可以識別這個注釋, 并在編譯C語言程序的時候?qū)⑺?dāng)作一個頭文件來處理. 在這個例子中, 它只是一個include語句, 然而其實(shí)它可以是使用有效的C語言代碼. 這個注釋必需緊靠在import "C"這個語句的上面, 不能有空行, 就像是文檔注釋一樣.

Strings and things

與Go語言不同, C語言中沒有顯式的字符串類型. 字符串在C語言中是一個以0結(jié)尾的字符數(shù)組.

Go和C語言中的字符串轉(zhuǎn)換是通過C.CString, C.GoString,和C.GoStringN這些函數(shù)進(jìn)行的. 這些轉(zhuǎn)換將得到字符串類型的一個副本.

下一個例子是實(shí)現(xiàn)一個Print函數(shù), 它使用C標(biāo)準(zhǔn)庫中的fputs函數(shù)把一個字符串寫到標(biāo)準(zhǔn)輸出上:

package print // #include stdio.h // #include stdlib.h import "C" import "unsafe" func Print(s string) { cs := C.CString(s) C.fputs(cs, (*C.FILE)(C.stdout)) C.free(unsafe.Pointer(cs)) }

在C程序中進(jìn)行的內(nèi)存分配是不能被Go語言的內(nèi)存管理器感知的. 當(dāng)你使用C.CString創(chuàng)建一個C字符串時(或者其它類型的C語言內(nèi)存分配), 你必需記得在使用完后用C.free來釋放它.

調(diào)用C.CString將返回一個指向字符數(shù)組開始處的指錯, 所以在函數(shù)退出前我們把它轉(zhuǎn)換成一個unsafe.Pointer(Go中與C的void 等價的東西), 使用C.free來釋放分配的內(nèi)存. 一個慣用法是在分配內(nèi)存后緊跟一個defer(特別是當(dāng)這段代碼比較復(fù)雜的時候), 這樣我們就有了下面這個Print函數(shù):

func Print(s string) { cs := C.CString(s) defer C.free(unsafe.Pointer(cs)) C.fputs(cs, (*C.FILE)(C.stdout)) }

構(gòu)建 cgo 包

如果你使用goinstall, 構(gòu)建cgo包就比較容易了, 只要調(diào)用像平常一樣使用goinstall命令, 它就能自動識別這個特殊的import "C", 然后自動使用cgo來編譯這些文件.

如果你想使用Go的Makefiles來構(gòu)建, 那在CGOFILES變量中列出那些要用cgo處理的文件, 就像GOFILES變量包含一般的Go源文件一樣.

rand包的Makefile可以寫成下面這樣:

include $(GOROOT)/src/Make.inc

TARG=goblog/rand

CGOFILES=\ rand.go\ include $(GOROOT)/src/Make.pkg

然后輸入gomake開始構(gòu)建.

更多 cgo 的資源

cgo的文檔中包含了關(guān)于C偽包的更多詳細(xì)的說明, 以及構(gòu)建過程. Go代碼樹中的cgo的例子給出了更多更高級的用法.

一個簡單而又符合Go慣用法的基于cgo的包是Russ Cox寫的gosqlite. 而Go語言的網(wǎng)站上也列出了更多的的cgo包.

最后, 如果你對于cgo的內(nèi)部是怎么運(yùn)作這個事情感到好奇的話, 去看看運(yùn)行時包的cgocall.c文件的注釋吧.

Go語言有什么優(yōu)勢?

GO語言的優(yōu)勢:可直接編譯成機(jī)器碼,不依賴其他庫,glibc的版本有一定要求,部署就是扔一個文件上去就完成了。靜態(tài)類型語言,但是有動態(tài)語言的感覺,靜態(tài)類型的語言就是可以在編譯的時候檢查出來隱藏的大多數(shù)問題,動態(tài)語言的感覺就是有很多的包可以使用,寫起來的效率很高。語言層面支持并發(fā),這個就是Go最大的特色,天生的支持并發(fā),我曾經(jīng)說過一句話,天生的基因和整容是有區(qū)別的,大家一樣美麗,但是你喜歡整容的還是天生基因的美麗呢?Go就是基因里面支持的并發(fā),可以充分的利用多核,很容易的使用并發(fā)。內(nèi)置runtime,支持垃圾回收,這屬于動態(tài)語言的特性之一吧,雖然目前來說GC不算完美,但是足以應(yīng)付我們所能遇到的大多數(shù)情況,特別是Go1.1之后的GC。簡單易學(xué),Go語言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go關(guān)鍵字是25個,但是表達(dá)能力很強(qiáng)大,幾乎支持大多數(shù)你在其他語言見過的特性:繼承、重載、對象等。豐富的標(biāo)準(zhǔn)庫,Go目前已經(jīng)內(nèi)置了大量的庫,特別是網(wǎng)絡(luò)庫非常強(qiáng)大,我最愛的也是這部分。內(nèi)置強(qiáng)大的工具,Go語言里面內(nèi)置了很多工具鏈,最好的應(yīng)該是gofmt工具,自動化格式化代碼,能夠讓團(tuán)隊(duì)review變得如此的簡單,代碼格式一模一樣,想不一樣都很困難??缙脚_編譯,如果你寫的Go代碼不包含cgo,那么就可以做到window系統(tǒng)編譯linux的應(yīng)用,如何做到的呢?Go引用了plan9的代碼,這就是不依賴系統(tǒng)的信息。Go語言這么多的優(yōu)勢,你還不想學(xué)嗎?我記得當(dāng)時我看的是黑馬程序員的視頻,我對他們視頻的印象就是通俗易懂,就是好!

go語言語法(基礎(chǔ)語法篇)

import "workname/packetfolder"

導(dǎo)入多個包

方法調(diào)用 包名.函數(shù)//不是函數(shù)或結(jié)構(gòu)體所處文件或文件夾名

packagename.Func()

前面加個點(diǎn)表示省略調(diào)用,那么調(diào)用該模塊里面的函數(shù),可以不用寫模塊名稱了:

當(dāng)導(dǎo)入一個包時,該包下的文件里所有init()函數(shù)都會被執(zhí)行,然而,有些時候我們并不需要把整個包都導(dǎo)入進(jìn)來,僅僅是是希望它執(zhí)行init()函數(shù)而已。下劃線的作用僅僅是為了調(diào)用init()函數(shù),所以無法通過包名來調(diào)用包中的其他函數(shù)

import _ package

變量聲明必須要使用否則會報錯。

全局變量運(yùn)行聲明但不使用。

func 函數(shù)名 (參數(shù)1,參數(shù)2,...) (返回值a 類型a, 返回值b 類型b,...)

func 函數(shù)名 (參數(shù)1,參數(shù)2,...) (返回值類型1, 返回值類型2,...)

func (this *結(jié)構(gòu)體名) 函數(shù)名(參數(shù) string) (返回值類型1, 返回值類型2){}

使用大小來區(qū)分函數(shù)可見性

大寫是public類型

小寫是private類型

func prifunc int{}

func pubfunc int{}

聲明靜態(tài)變量

const value int

定義變量

var value int

聲明一般類型、接口和結(jié)構(gòu)體

聲明函數(shù)

func function () int{}

go里面所有的空值對應(yīng)如下

通道類型

內(nèi)建函數(shù) new 用來分配內(nèi)存,它的第一個參數(shù)是一個類型,不是一個值,它的返回值是一個指向新分配類型零值的指針

func new(Type) *Type

[這位博主有非常詳細(xì)的分析]

Go 語言支持并發(fā),我們只需要通過 go 關(guān)鍵字來開啟 goroutine 即可。

goroutine 是輕量級線程,goroutine 的調(diào)度是由 Golang 運(yùn)行時進(jìn)行管理的。

同一個程序中的所有 goroutine 共享同一個地址空間。

語法格式如下:

通道(channel)是用來傳遞數(shù)據(jù)的一個數(shù)據(jù)結(jié)構(gòu)。

通道的聲明

通道可用于兩個 goroutine 之間通過傳遞一個指定類型的值來同步運(yùn)行和通訊。操作符 - 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。

[這里有比較詳細(xì)的用例]

go里面的空接口可以指代任何類型(無論是變量還是函數(shù))

聲明空接口

go里面的的強(qiáng)制類型轉(zhuǎn)換語法為:

int(data)

如果是接口類型的強(qiáng)制轉(zhuǎn)成其他類型的語法為:

go里面的強(qiáng)制轉(zhuǎn)換是將值復(fù)制過去,所以在數(shù)據(jù)量的時候有比較高的運(yùn)行代價

網(wǎng)頁題目:go語言內(nèi)存分布 go語言內(nèi)存占用
網(wǎng)頁鏈接:http://muchs.cn/article28/hgsdcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、定制網(wǎng)站、網(wǎng)站制作、App設(shè)計(jì)、做網(wǎng)站、定制開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司