go語言中新建類型 go語言能開發(fā)什么

Go語言中的結(jié)構(gòu)體

作為C語言家族的一員,go和c一樣也支持結(jié)構(gòu)體??梢灶惐扔趈ava的一個POJO。

我們提供的服務(wù)有:網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、新余ssl等。為上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的新余網(wǎng)站制作公司

在學(xué)習(xí)定義結(jié)構(gòu)體之前,先學(xué)習(xí)下定義一個新類型。

新類型 T1 是基于 Go 原生類型 int 定義的新自定義類型,而新類型 T2 則是 基于剛剛定義的類型 T1,定義的新類型。

這里要引入一個底層類型的概念。

如果一個新類型是基于某個 Go 原生類型定義的, 那么我們就叫 Go 原生類型為新類型的底層類型

在上面的例子中,int就是T1的底層類型。

但是T1不是T2的底層類型,只有原生類型才可以作為底層類型,所以T2的底層類型還是int

底層類型是很重要的,因為對兩個變量進行顯式的類型轉(zhuǎn)換,只有底層類型相同的變量間才能相互轉(zhuǎn)換。底層類型是判斷兩個類型本質(zhì)上是否相同的根本。

這種類型定義方式通常用在 項目的漸進式重構(gòu),還有對已有包的二次封裝方面

類型別名表示新類型和原類型完全等價,實際上就是同一種類型。只不過名字不同而已。

一般我們都是定義一個有名的結(jié)構(gòu)體。

字段名的大小寫決定了字段是否包外可用。只有大寫的字段可以被包外引用。

還有一個點提一下

如果換行來寫

Age: 66,后面這個都好不能省略

還有一個點,觀察e3的賦值

new返回的是一個指針。然后指針可以直接點號賦值。這說明go默認進行了取值操作

e3.Age 等價于 (*e3).Age

如上定義了一個空的結(jié)構(gòu)體Empty。打印了元素e的內(nèi)存大小是0。

有什么用呢?

基于空結(jié)構(gòu)體類型內(nèi)存零開銷這樣的特性,我們在日常 Go 開發(fā)中會經(jīng)常使用空 結(jié)構(gòu)體類型元素,作為一種“事件”信息進行 Goroutine 之間的通信

這種以空結(jié)構(gòu)體為元素類建立的 channel,是目前能實現(xiàn)的、內(nèi)存占用最小的 Goroutine 間通信方式。

這種形式需要說的是幾個語法糖。

語法糖1:

對于結(jié)構(gòu)體字段,可以省略字段名,只寫結(jié)構(gòu)體名。默認字段名就是結(jié)構(gòu)體名

這種方式稱為 嵌入字段

語法糖2:

如果是以嵌入字段形式寫的結(jié)構(gòu)體

可以省略嵌入的Reader字段,而直接訪問ReaderName

此時book是一個各個屬性全是對應(yīng)類型零值的一個實例。不是nil。這種情況在Go中稱為零值可用。不像java會導(dǎo)致npe

結(jié)構(gòu)體定義時可以在字段后面追加標簽說明。

tag的格式為反單引號

tag的作用是可以使用[反射]來檢視字段的標簽信息。

具體的作用還要看使用的場景。

比如這里的tag是為了幫助 encoding/json 標準包在解析對象時可以利用的規(guī)則。比如omitempty表示該字段沒有值就不打印出來。

Go語言中new和 make的區(qū)別詳解

1、new 的主要特性

首先 new 是內(nèi)建函數(shù),定義也很簡單:

func new(Type) *Type

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

實現(xiàn)一個類似 new 的功能:

func newInt() *int {

var i int

return i

}

someInt := newInt()

函數(shù)的功能跟 someInt := new(int) 一模一樣。定義 new 開頭的函數(shù)時,出于約定也應(yīng)該返回類型的指針。

2、make 的主要特性

make 也是內(nèi)建函數(shù),定義比 new 多了一個參數(shù),返回值也不同:

func make(Type, size IntegerType) Type

內(nèi)建函數(shù) make 用來為 slice,map 或 chan 類型分配內(nèi)存和初始化一個對象(注意:只能用在這三種類型上),跟 new 類似,第一個參數(shù)也是一個類型而不是一個值,跟 new 不同的是,make 返回類型的引用而不是指針,而返回值也依賴于具體傳入的類型,具體說明如下:

Slice: 第二個參數(shù) size 指定了長度,容量和長度相同。

可以傳入第三個參數(shù)來指定不同的容量值,但必須不能比長度值小。

比如 make([]int, 0, 10)

Map: 根據(jù) size 大小來初始化分配內(nèi)存,不過分配后的 map 長度為 0,如果 size 被忽略了,那么會在初始化分配內(nèi)存時分配一個小尺寸的內(nèi)存

Channel: 管道緩沖區(qū)依據(jù)緩沖區(qū)容量被初始化。如果容量為 0 或者忽略容量,管道沒有緩沖區(qū)。

3、總結(jié)

new 的作用是初始化一個指向類型的指針(*T),make 的作用是為 slice,map 或 chan 初始化并返回引用(T)。

Go語言的特點

類型 在變量名后邊

也可不顯式聲明類型, 類型推斷, 但是是靜態(tài)語言, name一開始放字符串就不能再賦值數(shù)字

方法,屬性 分開 方法名首字母大寫就是就是外部可調(diào)的

面向?qū)ο笤O(shè)計的一個重要原則:“優(yōu)先使用組合而不是繼承”

Dog 也是Animal , 要復(fù)用Animal 的屬性和方法,

只需要在結(jié)構(gòu)體 type 里面寫 Animal

入口也是main, 用用試試

多態(tài), 有這個方法就是這個接口的實現(xiàn), 具體的類 不需要知道自己實現(xiàn)了什么接口,

使用: 在一個函數(shù)調(diào)用之前加上關(guān)鍵字go 就啟動了一個goroutine

創(chuàng)建一個goroutine,它會被加入到一個全局的運行隊列當(dāng)中,

調(diào)度器 會把他們分配給某個 邏輯處理器 的隊列,

一個邏輯處理器 綁定到一個 操作系統(tǒng)線程 ,在上面運行g(shù)oroutine,

如果goroutine需要讀寫文件, 阻塞 ,就脫離邏輯處理器 直接 goroutine - 系統(tǒng)線程 綁定

編譯成同名.exe 來執(zhí)行, 不通過虛擬機, 直接是機器碼, 和C 一樣, 所以非常快

但是也有自動垃圾回收,每個exe文件當(dāng)中已經(jīng)包含了一個類似于虛擬機的runtime,進行g(shù)oroutine的調(diào)度

默認是靜態(tài)鏈接的,那個exe會把運行時所需要的所有東西都加進去,這樣就可以把exe復(fù)制到任何地方去運行了, 因此 生成的 .exe 文件非常大

Go語言基礎(chǔ)語法(一)

本文介紹一些Go語言的基礎(chǔ)語法。

先來看一個簡單的go語言代碼:

go語言的注釋方法:

代碼執(zhí)行結(jié)果:

下面來進一步介紹go的基礎(chǔ)語法。

go語言中格式化輸出可以使用 fmt 和 log 這兩個標準庫,

常用方法:

示例代碼:

執(zhí)行結(jié)果:

更多格式化方法可以訪問中的fmt包。

log包實現(xiàn)了簡單的日志服務(wù),也提供了一些格式化輸出的方法。

執(zhí)行結(jié)果:

下面來介紹一下go的數(shù)據(jù)類型

下表列出了go語言的數(shù)據(jù)類型:

int、float、bool、string、數(shù)組和struct屬于值類型,這些類型的變量直接指向存在內(nèi)存中的值;slice、map、chan、pointer等是引用類型,存儲的是一個地址,這個地址存儲最終的值。

常量是在程序編譯時就確定下來的值,程序運行時無法改變。

執(zhí)行結(jié)果:

執(zhí)行結(jié)果:

Go 語言的運算符主要包括算術(shù)運算符、關(guān)系運算符、邏輯運算符、位運算符、賦值運算符以及指針相關(guān)運算符。

算術(shù)運算符:

關(guān)系運算符:

邏輯運算符:

位運算符:

賦值運算符:

指針相關(guān)運算符:

下面介紹一下go語言中的if語句和switch語句。另外還有一種控制語句叫select語句,通常與通道聯(lián)用,這里不做介紹。

if語法格式如下:

if ... else :

else if:

示例代碼:

語法格式:

另外,添加 fallthrough 會強制執(zhí)行后面的 case 語句,不管下一條case語句是否為true。

示例代碼:

執(zhí)行結(jié)果:

下面介紹幾種循環(huán)語句:

執(zhí)行結(jié)果:

執(zhí)行結(jié)果:

也可以通過標記退出循環(huán):

--THE END--

為什么 Go 語言把類型放在后面

不是為了與眾不同。而是為了更加清晰易懂。

Rob Pike 曾經(jīng)在 Go 官方博客解釋過這個問題(原文地址:),簡略翻譯如下(水平有限翻譯的不對的地方見諒):

引言

Go語言新人常常會很疑惑為什么這門語言的聲明語法(declaration syntax)會和傳統(tǒng)的C家族語言不同。在這篇博文里,我們會進行一個比較,并做出解答。

C 的語法

首先,先看看 C 的語法。C 采用了一種聰明而不同尋常的聲明語法。聲明變量時,只需寫出一個帶有目標變量名的表達式,然后在表達式里指明該表達式本身的類型即可。比如:

int x;

上面的代碼聲明了 x 變量,并且其類型為 int——即,表達式 x 為 int 類型。一般而言,為了指明新變量的類型,我們得寫出一個表達式,其中含有我們要聲明的變量,這個表達式運算的結(jié)果值屬于某種基本類型,我們把這種基本類型寫到表達式的左邊。所以,下述聲明:

int *p;

int a[3];

指明了 p 是一個int類型的指針,因為 *p 的類型為 int。而 a 是一個 int 數(shù)組,因為 a[3] 的類型為 int(別管這里出現(xiàn)的索引值,它只是用于指明數(shù)組的長度)。

我們接下來看看函數(shù)聲明的情況。C 的函數(shù)聲明中關(guān)于參數(shù)的類型是寫在括號外的,像下面這樣:

int main(argc, argv)

int argc;

char *argv[];

{ /* ... */ }

如前所述,我們可以看到 main 之所以是函數(shù),是因為表達式 main(argc, argv) 返回 int。在現(xiàn)代記法中我們是這么寫的:

int main(int argc, char *argv[]) { /* ... */ }

盡管看起來有些不同,但是基本的結(jié)構(gòu)是一樣的。

總的來看,當(dāng)類型比較簡單時,C的語法顯得很聰明。但是遺憾的是一旦類型開始復(fù)雜,C的這套語法很快就能讓人迷糊了。著名的例子如函數(shù)指針,我們得按下面這樣來寫:

int (*fp)(int a, int b);

在這兒,fp 之所以是一個指針是因為如果你寫出 (*fp)(a, b) 這樣的表達式將會調(diào)用一個函數(shù),其返回 int 類型的值。如果當(dāng) fp 的某個參數(shù)本身又是一個函數(shù),情況會怎樣呢?

int (*fp)(int (*ff)(int x, int y), int b)

這讀起來可就點難了。

當(dāng)然了,我們聲明函數(shù)時是可以不寫明參數(shù)的名稱的,因此 main 函數(shù)可以聲明為:

int main(int, char *[])

回想一下,之前 argv 是下面這樣的

char *argv[]

你有沒有發(fā)現(xiàn)你是從聲明的「中間」去掉變量名而后構(gòu)造出其變量類型的?盡管這不是很明顯,但你聲明某個 char *[] 類型的變量的時候,竟然需要把名字插入到變量類型的中間。

我們再來看看,如果我們不命名 fp 的參數(shù)會怎樣:

int (*fp)(int (*)(int, int), int)

這東西難懂的地方可不僅僅是要記得參數(shù)名原本是放這中間的

int (*)(int, int)

它更讓人混淆的地方還在于甚至可能都搞不清這竟然是個函數(shù)指針聲明。我們接著看看,如果返回值也是個函數(shù)指針類型又會怎么樣

int (*(*fp)(int (*)(int, int), int))(int, int)

這已經(jīng)很難看出是關(guān)于 fp 的聲明了。

你自己還可以構(gòu)建出比這更復(fù)雜的例子,但這已經(jīng)足以解釋 C 的聲明語法引入的某些復(fù)雜性了。

還有一點需要指出,由于類型語法和聲明語法是一樣的,要解析中間帶有類型的表達式可能會有些難度。這也就是為什么,C 在做類型轉(zhuǎn)換的時候總是要把類型用括號括起來的原因,像這樣

(int)M_PI

Go 的語法

非C家族的語言通常在聲明時使用一種不同的類型語法。一般是名字先出現(xiàn),然后常常跟著一個冒號。按照這樣來寫,我們上面所舉的例子就會變成下面這樣:

x: int

p: pointer to int

a: array[3] of int

這樣的聲明即便有些冗長,當(dāng)至少是清晰的——你只需從左向右讀就行。Go 語言所采用的方案就是以此為基礎(chǔ)的,但為了追求簡潔性,Go 語言丟掉了冒號并去掉了部分關(guān)鍵詞,成了下面這樣:

x int

p *int

a [3]int

在 [3]int 和表達式中 a 的用法沒有直接的對應(yīng)關(guān)系(我們在下一節(jié)會回過頭來探討指針的問題)。至此,你獲得了代碼清晰性方面的提升,但付出的代價是語法上需要區(qū)別對待。

下面我們來考慮函數(shù)的問題。雖然在 Go 語言里,main 函數(shù)實際上沒有參數(shù),但是我們先謄抄一下之前的 main 函數(shù)的聲明:

func main(argc int, argv *[]byte) int

粗略一看和 C 沒什么不同,不過自左向右讀的話還不錯。

main 函數(shù)接受一個 int 和一個指針并返回一個 int。

如果此時把參數(shù)名去掉,它還是很清楚——因為參數(shù)名總在類型的前面,所以不會引起混淆。

func main(int, *[]byte) int

這種自左向右風(fēng)格的聲明的一個價值在于,當(dāng)類型變得更復(fù)雜時,它依然相對簡單。下面是一個函數(shù)變量的聲明(相當(dāng)于 C 語言里的函數(shù)指針)

f func(func(int,int) int, int) int

或者當(dāng)它返回一個函數(shù)時:

f func(func(int,int) int, int) func(int, int) int

上面的聲明讀起來還是很清晰,自左向右,而且究竟哪一個變量名是當(dāng)前被聲明的也容易看懂——因為變量名永遠在首位。

類型語法和表達式語法帶來的差別使得在 Go 語言里調(diào)用閉包也變得更簡單:

sum := func(a, b int) int { return a+b } (3, 4)

指針

指針有些例外。注意在數(shù)組 (array )和切片 (slice) 中,Go 的類型語法把方括號放在了類型的左邊,但是在表達式語法中卻又把方括號放到了右邊:

var a []int

x = a[1]

類似的,Go 的指針沿用了 C 的 * 記法,但是我們寫的時候也是聲明時 * 在變量名右邊,但在表達式中卻又得把 * 放到左左邊:

var p *int

x = *p

不能寫成下面這樣

var p *int

x = p*

因為后綴的 * 可能會和乘法運算混淆,也許我們可以改用 Pascal 的 ^ 標記,像這樣

var p ^int

x = p^

我們也許還真的應(yīng)該把 * 像上面這樣改成 ^ (當(dāng)然這么一改 xor 運算的符號也得改),因為在類型和表達式中的 * 前綴確實把好些事兒都搞得有點復(fù)雜,舉個例子來說,雖然我們可以像下面這樣寫

[]int("hi")

但在轉(zhuǎn)換時,如果類型是以 * 開頭的,就得加上括號:

(*int)(nil)

如果有一天我們愿意放棄用 * 作為指針語法的話,那么上面的括號就可以省略了。

可見,Go 的指針語法是和 C 相似的。但這種相似也意味著我們無法徹底避免在文法中有時為了避免類型和表達式的歧義需要補充括號的情況。

總而言之,盡管存在不足,但我們相信 Go 的類型語法要比 C 的容易懂。特別是當(dāng)類型比較復(fù)雜時。

本文題目:go語言中新建類型 go語言能開發(fā)什么
轉(zhuǎn)載源于:http://muchs.cn/article38/dooogsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、品牌網(wǎng)站設(shè)計、軟件開發(fā)、品牌網(wǎng)站制作、網(wǎng)站營銷、域名注冊

廣告

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

綿陽服務(wù)器托管