溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Go數(shù)據(jù)類型實(shí)例分析

發(fā)布時(shí)間:2022-04-18 10:57:40 來(lái)源:億速云 閱讀:139 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容介紹了“Go數(shù)據(jù)類型實(shí)例分析”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

每一個(gè)變量都有數(shù)據(jù)類型,Go中的數(shù)據(jù)類型有:

  • 簡(jiǎn)單數(shù)據(jù)類型:int、float、complex、bool和string

  • 數(shù)據(jù)結(jié)構(gòu)或組合(composite):struct、array、slice、map和channel

  • 接口(interface)

當(dāng)聲明變量的時(shí)候,會(huì)做默認(rèn)的賦0初始化。每種數(shù)據(jù)類型的默認(rèn)賦0初始化的0值不同,例如int類型的0值為數(shù)值0,float的0值為0.0,string類型的0值為空"",bool類型的0值為false,數(shù)據(jù)結(jié)構(gòu)的0值為nil,struct的0值為字段全部賦0。

其實(shí)函數(shù)也有類型,不過(guò)一般稱之為返回類型。例如,下面的函數(shù)foo的返回類型是int:

func foo() int {
    ...CODE...
    return INT_TYPE_VALUE
}

函數(shù)允許有多個(gè)返回值,它們使用逗號(hào)分隔,括號(hào)包圍:

func foo() (int,bool)

Number類型

Integer

Integer類型是整型數(shù)據(jù),例如3 22 0 1 -3 -22等。

Go中的Integer有以下幾種細(xì)分的類型:

  • int8,int16,int32,int64

  • uint8,uint16,uint32,uint64

  • byte

  • rune

  • int,uint

其中8 16 32 64表示該數(shù)據(jù)類型能存儲(chǔ)的bit位數(shù)。例如int8表示能存儲(chǔ)8位數(shù)值,所以這個(gè)類型占用1字節(jié),也表示最大能存儲(chǔ)的整型數(shù)共2^8=256個(gè),所以int8類型允許的最大正數(shù)為127,允許的最小負(fù)數(shù)為-128,共256個(gè)數(shù)值。

uint中的u表示unsigned,即無(wú)符號(hào)整數(shù),只保存0和正數(shù)。所以u(píng)int8能存儲(chǔ)256個(gè)數(shù)的時(shí)候,允許的最小值為0,允許的最大值為255。

額外的兩種Integer是byte和rune,它們分別等價(jià)于uint8(即一個(gè)字節(jié)大小的正數(shù))、int32。從builtin包中的定義就可以知道:

$ go doc builtin | grep -E "byte|rune"
type byte = uint8
type rune = int32

byte類型后面會(huì)詳細(xì)解釋。

還有兩種依賴于CPU位數(shù)的類型int和uint,它們分別表示一個(gè)機(jī)器字長(zhǎng)。在32位CPU上,一個(gè)機(jī)器字長(zhǎng)為32bit,共4字節(jié),在64位CPU上,一個(gè)機(jī)器字長(zhǎng)為64bit,共8字節(jié)。除了int和uint依賴于CPU架構(gòu),還有一種uintptr也是依賴于機(jī)器字長(zhǎng)的。

一般來(lái)說(shuō),需要使用整型數(shù)據(jù)的時(shí)候,指定int即可,有明確的額外需求時(shí)再考慮是否換成其它整數(shù)類型。

在整數(shù)加上0前綴表示這是8進(jìn)制,例如077。加上前綴0x表示這是16進(jìn)制,例如0x0c,使用e符號(hào)可以表示這是一個(gè)科學(xué)計(jì)數(shù)法,如1e3 = 1000,6.023e23 = 6.023 x 10^23。

可以使用TYPE(N)的方式來(lái)生成一個(gè)數(shù)值,例如a := uint64(5)。實(shí)際上這是類型轉(zhuǎn)換,將int類型的5轉(zhuǎn)換成int64類型的5。

byte類型

Go中沒(méi)有專門提供字符類型char,Go內(nèi)部的所有字符類型(無(wú)論是ASCII字符還是其它多字節(jié)字符)都使用整數(shù)值保存,所以字符可以存放到byte、int等數(shù)據(jù)類型變量中。byte類型等價(jià)于uint8類型,表示無(wú)符號(hào)的1字節(jié)整數(shù)。

Go中的字符都使用單引號(hào)包圍,例如'a''我',但單引號(hào)中包含了多個(gè)字符是錯(cuò)誤的(如'aA'),因?yàn)樽址愋途褪且粋€(gè)字符。

例如,ASCII的字母a表示97。下面這種定義方式是允許的:

var a byte = 'A'  // a=65
var b uint8 = 'a' // b=97

注意,字符必須使用單引號(hào),且必須只能是單個(gè)字符。所以byte類型經(jīng)常被稱為character類型。

以下也都是允許的:

var a = 'A'
var a uint32 = 'A'
var a int64 = 'A'

所以,Integer類型當(dāng)存儲(chǔ)的是以單引號(hào)包圍的字符時(shí),它會(huì)將字符轉(zhuǎn)換成它二進(jìn)制值對(duì)應(yīng)的數(shù)值。同樣適用于unicode字符,它將用來(lái)存放各字節(jié)對(duì)應(yīng)的二進(jìn)制的數(shù)值:

var a int64 = '我'  // a=25105

由于在Go中占用3字節(jié),所以保存到byte中是報(bào)錯(cuò)的:

var a byte = '我'

可以保存它的unicode字符的代碼點(diǎn):

var a byte = '\u0041'  // a=65,代表的字符A

如果不知道代碼點(diǎn)的值,可以將其以int類型保存并輸出。

fmt.Printf("%d", '我')  // 25105

如果想將byte值轉(zhuǎn)換為字符,可以使用string()函數(shù)做簡(jiǎn)單的類型轉(zhuǎn)換:

var a = 'A'
println(string(a))     // 輸出:A

float和complex

float是浮點(diǎn)數(shù)(俗稱小數(shù)),例如0.0 3.0 -3.12 -3.120等。

Go中的浮點(diǎn)數(shù)類型float有兩種:float32和float64。

complex表示復(fù)數(shù)類型(虛數(shù)),有complex64和complex128。

浮點(diǎn)數(shù)在計(jì)算機(jī)系統(tǒng)中非常復(fù)雜,對(duì)于學(xué)習(xí)來(lái)說(shuō),只需將其認(rèn)為是數(shù)學(xué)中的一種小數(shù)即可。但以下幾個(gè)注意點(diǎn)需要謹(jǐn)記心中:

  • 浮點(diǎn)數(shù)是不精確的。例如1.01-0.99從數(shù)學(xué)運(yùn)算的角度上得到的值是0.02,但實(shí)際上的結(jié)果是0.020000000000000018(python運(yùn)算的結(jié)果),在Go中會(huì)將其表示為+2.000000e-002。這個(gè)結(jié)果是一種極限趨近于我們期待值的結(jié)果。

  • float32的精度(7個(gè)小數(shù)位)低于float64(15個(gè)小數(shù)位),所以float64類型的值比f(wàn)loat32類型的值更精確。

  • 因?yàn)楦↑c(diǎn)數(shù)不精確,所以盡量不要對(duì)兩個(gè)浮點(diǎn)數(shù)數(shù)進(jìn)行等值==和不等值!=比較,例如(3.2-2.8) == 0.4返回Flase。如果非要比較,應(yīng)該通過(guò)它們的減法求絕對(duì)值,再與一個(gè)足夠小(不會(huì)影響結(jié)果)的值做不等比較,例如abs((3.2-2.8)-0.4) < 0.0002返回True。

一般來(lái)說(shuō),在程序中需要使用浮點(diǎn)數(shù)的時(shí)候都使用float64類型,不僅因?yàn)榫_,更因?yàn)閹缀跛邪行枰猣loat參數(shù)的類型都是float64。

在Go的數(shù)學(xué)運(yùn)算中,默認(rèn)取的是整型數(shù)據(jù),如果想要得到浮點(diǎn)數(shù)結(jié)果,必須至少讓運(yùn)算的一方寫成浮點(diǎn)數(shù)格式:

var a := 3/2     // a得到截?cái)嗟恼麛?shù):a=1
var b := 3/2.0   // b為浮點(diǎn)數(shù)b=+1.500000e+000
var c := 3 + 2.0 // c為浮點(diǎn)數(shù)

string類型

Go中的string用于保存UTF-8字符序列,它是動(dòng)態(tài)大小的。對(duì)于字母和英文字母,它占用一個(gè)字節(jié),對(duì)于其它unicode字符,按需占用2-4個(gè)字節(jié)。例如中文字符占用3個(gè)字節(jié)。

Go中的string類型要使用雙引號(hào)或反引號(hào)包圍,它們的區(qū)別是:

  • 雙引號(hào)是弱引用,其內(nèi)可以使用反斜線轉(zhuǎn)義符號(hào),如ab\ncd表示ab后換行加cd

  • 反引號(hào)是強(qiáng)引用,其內(nèi)任何符號(hào)都被強(qiáng)制解釋為字面意義,包括字面的換行。也就是所謂的裸字符串。

func main() {
    println("abc\ndef")
    println(`ABC
    DEF`)
}

上面的結(jié)果將輸出:

abc
def
ABC
    DEF

不能使用單引號(hào)包圍,單引號(hào)包圍的表示它的二進(jìn)制值轉(zhuǎn)換成十進(jìn)制的數(shù)值。例如字母對(duì)應(yīng)的是ASCII碼。這個(gè)在前面byte類型中介紹過(guò)。所以,使用單引號(hào)包圍的字符實(shí)際上是整數(shù)數(shù)值。例如'a'等價(jià)于97。

string的底層是byte數(shù)組,每個(gè)string其實(shí)只占用兩個(gè)機(jī)器字長(zhǎng):一個(gè)指針和一個(gè)長(zhǎng)度。只不過(guò)這個(gè)指針在Go中完全不可見(jiàn),所以對(duì)我們來(lái)說(shuō),string是一個(gè)底層byte數(shù)組的值類型而非指針類型。

Go數(shù)據(jù)類型實(shí)例分析

所以,可以將一個(gè)string使用append()或copy()拷貝到一個(gè)給定的byte slice中,也可以使用slice的切片功能截取string中的片段。

func main() {
	var a = "Hello Gaoxiaofang"
	println(a[2:3])      // 輸出:l

	s1 := make([]byte,30)
	copy(s1,a)          // 將字符串保存到slice中
	println(string(s1)) // 輸出"Hello Gaoxiaofang"
}

字符串串接

使用加號(hào)+連接兩段字符串:"Hello" + "World"等價(jià)于"HelloWorld"。

可以通過(guò)+的方式將多行連接起來(lái)。例如:

str := "Beginning string "+
       "second string"

字符串連接+操作符強(qiáng)制認(rèn)為它兩邊的都是string類型,所以"abcd" + 2將報(bào)錯(cuò)。需要先將int類型的2轉(zhuǎn)換為字符串類型(不能使用string(2)的方式轉(zhuǎn)換,因?yàn)檫@種轉(zhuǎn)換方式不能跨大類型轉(zhuǎn)換,只能使用strconv包中的函數(shù)轉(zhuǎn)換)。

另一種更高效的字符串串接方式是使用strings包中的Join()函數(shù),它可以在緩沖中將字符串串接起來(lái)。

字符串長(zhǎng)度

使用len()取字節(jié)數(shù)量(不是字符數(shù)量)。

例如len("abcde")返回5,size(我是中國(guó)人)返回15。

字符串截取

可以將字符串當(dāng)作數(shù)組,使用索引號(hào)取部分字符串(按字節(jié)計(jì)算),索引號(hào)從0開(kāi)始計(jì)算,如"abcd"[1]。

從字符串取字符的時(shí)候,需要注意的是index按字節(jié)計(jì)算而非按字符計(jì)算。兩種取數(shù)據(jù)方式:

"string"[x]
"string"[x:y]

第一種方式將返回第(x+1)個(gè)字節(jié)對(duì)應(yīng)字符的二進(jìn)制數(shù)值,例如字母將轉(zhuǎn)換為ASCII碼,unicode將取對(duì)應(yīng)字節(jié)的二進(jìn)制轉(zhuǎn)換為數(shù)值。

第二種方式將返回第(x+1)字節(jié)到第y字節(jié)中間的字符,Go中采取"左閉右開(kāi)"的方式,所以所截取部分包括index=x,但不包括index=y。

例如:

func main() {
    println("abcde"[1])          // (1).輸出"98"
    println("我是中國(guó)人"[1])       // (2).輸出"136"
    println("abcde"[0:2])        // (3).輸出"ab"
    println("我是中國(guó)人"[0:3])     // (4).輸出"我"
    println("abcde"[3:4])        // (5).輸出"d"
}

分析每一行語(yǔ)句:

  • (1).取第2個(gè)字節(jié)的二進(jìn)制值,即字符b對(duì)應(yīng)的值,其ASCII為98

  • (2).取第2個(gè)字節(jié)的二進(jìn)制值,因?yàn)橹形恼加?個(gè)字節(jié),所以取第一個(gè)字符"我"的第二個(gè)字節(jié)部分,轉(zhuǎn)換為二進(jìn)制值,為136

  • (3).取第1個(gè)字節(jié)到第3個(gè)字節(jié)(不包括)中間的字符,所以輸出"ab"

  • (4).取前三個(gè)字節(jié)對(duì)應(yīng)的字符,所以輸出"我"

  • (5).取第4個(gè)字節(jié)對(duì)應(yīng)的字符,所以輸出d

字符串遍歷

字符串是字符數(shù)組,如果字符串中全是ASCII字符,直接遍歷即可,但如果包含了多字節(jié)字符,則可以[]rune(str)轉(zhuǎn)換后后再遍歷。

package main

import "fmt"

func main() {
	str := "Hello 你好"
	r := []rune(str)  // 8
	for i := 0; i < len(r); i++ {
		fmt.Printf("%c", r[i])
	}
}

字符串比較

可以使用< <= > >= == !=對(duì)字符串進(jìn)行比較,它將一個(gè)字符一個(gè)字符地比對(duì)。字母以A-Za-z的ASCII方式排列。

// 字符串比較
println("a" < "B")  // false

// 數(shù)值比較,不是字符串比較
println('a' == 97)  // true

修改字符串

字符串是一個(gè)不可變對(duì)象,所以對(duì)字符串s截取后賦值的方式s[1]="c"會(huì)報(bào)錯(cuò)。

要想修改字符串中的字符,必須先將字符串拷貝到一個(gè)byte slice中,然后修改指定索引位置的字符,最后將byte slice轉(zhuǎn)換回string類型。

例如,將"gaoxiaofang"改為"maoxiaofang":

s := "gaoxiaofang"
bs := []byte(s)
bs[0] = 'm'     // 必須使用單引號(hào)
s = string(bs)
println(s)

注意修改字符的時(shí)候,必須使用單引號(hào),因?yàn)樗莃yte類型。

布爾類型(bool)

bool類型的值只有兩種:true和false。

有3種布爾邏輯運(yùn)算符:&& || !,分別別是邏輯與,邏輯或,取反。

func main() {
    println(true && true)    // true
    println(true && false)   // false
    println(true || true)    // true
    println(true || false)   // true
    println(!true)           // false
}

Go是一門非常嚴(yán)格的怨言,在使用==進(jìn)行等值比較的時(shí)候,要求兩邊的數(shù)據(jù)類型必須相同,否則報(bào)錯(cuò)。如果兩邊數(shù)據(jù)類型是接口類型,則它們必須實(shí)現(xiàn)相同的接口函數(shù)。如果是常量比較,則兩邊必須是能夠兼容的數(shù)據(jù)類型。

在printf類的函數(shù)的格式中,占位符%t用于代表布爾值。

布爾類型的變量、函數(shù)名應(yīng)該以is或Is的方式開(kāi)頭來(lái)表明這是一個(gè)布爾類型的東西。例如isSorted()函數(shù)用于檢測(cè)內(nèi)容是否已經(jīng)排序,IsFinished()用于判斷是否完成。

type關(guān)鍵字:類型別名

可以使用type定義自己的數(shù)據(jù)類型,例如struct、interface。

還可以使用type定義類型的別名。例如,定義一個(gè)int類型的別名INT:

type INT int

這樣INT類型的底層數(shù)據(jù)結(jié)構(gòu)還是int類型。可以將它和int一樣使用:

var a INT = 5

type中可以一次性聲明多個(gè)別名:

type (
    CT int
    IT int32
    DT float32
)

獲取數(shù)據(jù)類型

reflect包的TypeOf(),或者Printf/Sprintf的"%T"。

package main

import (
	"reflect"
	"fmt"
)

type IT int32
func main() {
	var a IT = 322
	var b = 22
	fmt.Println(reflect.TypeOf(a))   // main.IT
	fmt.Println(reflect.TypeOf(b))   // int
	fmt.Println(fmt.Sprintf("%T", a)) // main.IT
}

數(shù)據(jù)類型的大小

unsafe包的Sizeof()查看變量或常量所屬數(shù)據(jù)類型占用空間的大小。

package main

import (
	"unsafe"
	"fmt"
)

type IT int32
func main() {
	var a IT = 322
	var b = 22
	fmt.Println(unsafe.Sizeof(a)) // 4
	fmt.Println(unsafe.Sizeof(b)) // 8
}

“Go數(shù)據(jù)類型實(shí)例分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

go
AI