Go語言學習(四)常用類型介紹

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1.布爾類型

var v1 boolv1 = true;v2 := (1==2) // v2也會被推導為bool類型

2.整型

類 型  長度(位元組)     值 範 圍int8    1              128 ~ 127uint8(即byte)1       0 ~ 255int16   2              32 768 ~ 32 767uint16  2               0 ~ 65 535int32   4              2 147 483 648 ~ 2 147 483 647uint32  4               0 ~ 4 294 967 295int64   8      9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807uint64  8       0 ~ 18 446 744 073 709 551 615int     平台相關        平台相關uint    平台相關        平台相關uintptr 同指標         在32位平台下為4位元組,64位平台下為8位元組var value2 int32value1 := 64 // value1將會被自動推導為int類型value2 =value1  //編譯失敗:cannot use value1 (type int) as type int32 in assignment。//使用強制類型轉換可解決value2 = int32(value1)

3.數值運算

常規運算:+、-、*、/和%比較運算: > 、 < 、 == 、 >= 、 <= 和 !=需要注意:兩個不同類型的整型數不能直接比較,比如 int8 類型的數和 int類型的數不能直接比較,但各種類型的整型變數都可以直接與字面常量(literal)進行比較,比如:
var i int32var j int64i, j = 1, 2if i == j { // 編譯錯誤fmt.Println("i and j are equal.")}if i == 1 || j == 2 { // 編譯通過fmt.Println("i and j are equal.")}

4.位元運算

x << y  左移 x >> y  右移 x ^ y   異或  x & y   與  x | y   或 ^x      取反  

5.浮點類型

Go語言定義了兩個類型 float32 和 float64 ,其中 float32 等價於C語言的 float 類型,float64 等價於C語言的 double 類型。var fvalue1 float32fvalue1 = 12fvalue2 := 12.0 // 如果不加小數點,fvalue2會被推導為整型而不是浮點型對於以上例子中類型被自動推導的 fvalue2 ,需要注意的是其類型將被自動設為 float64 ,而不管賦給它的數字是否是用32位長度表示的。因此,對於以上的例子,下面的賦值將導致編譯錯誤:fvalue1 = fvalue2而必須使用這樣的強制類型轉換:fvalue1 = float32(fvalue2)

5.1浮點數比較

因為浮點數不是一種精確的表達方式,所以像整型那樣直接用 == 來判斷兩個浮點數是否相等是不可行的,這可能會導致不穩定的結果。下面是一種推薦的替代方案:
import "math"// p為使用者自訂的比較精度,比如0.00001func IsEqual(f1, f2, p float64) bool {    return math.Fdim(f1, f2) < p}

6.複數

複數實際上由兩個實數(在電腦中用浮點數表示)構成,一個表示實部(real),一個表示虛部(imag)。如果瞭解了數學上的複數是怎麼回事,那麼Go語言的複數就非常容易理解了。

6.1複數表示

var value1 complex64 // 由2個float32構成的複數類型value1 = 3.2 + 12ivalue2 := 3.2 + 12i // value2是complex128類型value3 := complex(3.2, 12) // value3結果同 value2

6.2 實部與虛部

對於一個複數 z = complex(x, y) ,就可以通過Go語言內建函數 real(z) 獲得該複數的實部,也就是 x ,通過 imag(z) 獲得該複數的虛部,也就是 y 。

7.字串

Go語言中字串的聲明和初始化非常簡單,舉例如下:
var str string  // 聲明一個字串變數str = "Hello world" // 字串賦值ch := str[0] // 取字串的第一個字元fmt.Printf("The length of \"%s\" is %d \n", str, len(str))fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)
輸出結果為:The length of "Hello world" is 11The first character of "Hello world" is H.
字串的內容可以用類似於數組下標的方式擷取,但與數組不同,字串的內容不能在初始化後被修改,比如以下的例子:str := "Hello world" // 字串也支援聲明時進行初始化的做法str[0] = 'X'  // 編譯錯誤編譯器會報類似如下的錯誤:cannot assign to str[0]如果想修改字串的內容,可以通過如下的方式修改:
s := "hello"c := []rune(s) //將字串s轉成rune數組c[0] = 'x' //修改rune數組中的第一個元素為xs2 := string(c) //根據rune數組建立一個新的字串fmt.Println("s2=",s2)
運行結果:    s2= xello

7.1字串操作

x + y   字串串連  "Hello" + "123" // 結果為Hello123len(s)  字串長度  len("Hello") // 結果為5s[i]    取字元  "Hello" [1] // 結果為'e'

7.2多行字串

使用多行字串需要小心,例如:s := "Hello "    +"world"編譯時間會被自動轉換成:s := "Hello ";    +"world";此時會編譯失敗,報錯:invalid operation: + untyped string  正確的多行寫法是這樣的:s := "Hello " +    "world"Go 就不會在錯誤的地方插入分號。另一種寫法是使用反引號 ` 作為原始字串符號:s := `Hello      world`

7.3字串遍曆

Go語言支援兩種方式遍曆字串。一種是以位元組數組的方式遍曆:
str := "abc中國"n := len(str)for i := 0; i < n; i++ {    ch := str[i] // 依據下標取字串中的字元,類型為byte    fmt.Printf("i=%v\n", ch)}
輸出結果:i=97    //ai=98    //bi=99    //ci=228   //中字的第一位元組,每個中文字元在UTF-8中佔3個位元組i=184   //中字的第二個位元組i=173   //中字的第三個位元組i=229   //國字的第一個位元組i=155   //國字的第二個位元組i=189   //國字的第三個位元組
另一種是以Unicode字元遍曆,以Unicode字元方式遍曆時,每個字元的類型是 rune (早期的Go語言用 int 類型表示Unicode字元),而不是byte.
str := "abc中國"for i, ch := range str{  //range關鍵字在數組中有介紹    fmt.Println(i,ch)  //ch的類型為rune}
//輸出結果:0 971 982 993 20013   6 22269

8.字元類型

在Go語言中支援兩個字元類型,一個是 byte (實際上是 uint8 的別名),代表UTF-8字串的單個位元組的值;另一個是 rune ,代表單個Unicode字元。出於簡化語言的考慮,Go語言的多數API都假設字串為UTF-8編碼。儘管Unicode字元在標準庫中有支援,但實際上較少使用。

9.數組

以下為一些常規的數組聲明方法:[32]byte // 長度為32的數組,每個元素為一個位元組[2*N] struct { x, y int32 } // 複雜類型數組[1000]*float64  // 指標數組[3][5]int  // 二維數組[2][2][2]float64  // 等同於[2]([2]([2]float64))在Go語言中,數組長度在定義後就不可更改,在聲明時間長度度可以為一個常量或者一個常量運算式(常量運算式是指在編譯期即可計算結果的運算式)。

9.1元素的訪問

可以使用數組下標來訪問數組中的元素。與C語言相同,數組下標從0到len(array)-1,下面的樣本遍曆整型數組並逐個列印元素內容:
//通過for迴圈遍曆for i := 0; i < len(array); i++ {    fmt.Println("Element", i, "of array is", array[i])}//Go語言還提供了一個關鍵字range,用於便捷地遍曆容器中的元素。//當然,數組也是range的支援範圍。上面的遍曆過程可以簡化為如下的寫法:for k, v := range array {  //k相當於索引,v相當於值    fmt.Println("Array element[", k, "]=", v)  }

9.2值操作

需要特別注意的是,在Go語言中數組是一個實值型別(value type)。所有的實值型別變數在賦值和作為參數傳遞時都將產生一次複製動作。如果將數組作為函數的參數類型,則在函數調用時該參數將發生資料複製。因此,在函數體中無法修改傳入的數組的內容,因為函數內操作的只是所傳入數組的一個副本。下面用例子來說明這一特點:
func main(){    array := [5]int{1,2,3,4,5}    modify(array)    fmt.Println("In main(),array values:",array)}func modify(array [5] int){    array[0] = 10    fmt.Println("In modify(),array values:",array)}
//輸出結果:In modify(), array values: [10 2 3 4 5]In main(), array values: [1 2 3 4 5]
從執行結果可以看出,函數 modify() 內操作的那個數組跟 main() 中傳入的數組是兩個不同的執行個體。那麼,如何才能在函數內操作外部的資料結構呢?這個就要用到後接下來要講的數組切片.

10.數組切片

在前一節裡我們已經提過數組的特點:數組的長度在定義之後無法再次修改;數組是實值型別,每次傳遞都將產生一份副本。顯然這種資料結構無法完全滿足開發人員的真實需求。Go語言提供了數組切片(slice)這個非常酷的功能來彌補數組的不足,可以隨時動態擴充存放空間,並且可以被隨意傳遞而不會導致所管理的元素被重複復制。有點類似於java中的集合.數組切片的資料結構可以抽象為以下3個變數:一個指向原生數組的指標;數組切片中的元素個數;數組切片已指派的儲存空間。

10.1建立數組切片

(1)基於已存在數組建立,數組切片可以只使用數組的一部分元素或者整個數組來建立,甚至可以建立一個比所基於的數組還要大的數組切片。
var myArray [10]int = [10]int{1,2,3,4,5,6,7,8,9,10}// 基於數組前5個元素建立一個數組切片var mySlice []int = myArray[:5]fmt.Println("Elements of myArray:")for _, v := range myArray{    fmt.Print(v," ")}fmt.Println("\nElements of mySlice:")for _, v:= range mySlice{    fmt.Print(v," ")}
//輸出結果:Elements of myArray:1 2 3 4 5 6 7 8 9 10Elements of mySlice:1 2 3 4 5
Go語言支援用 myArray[first:last] 這樣的方式來基於數組產生一個數組切片,而且這個用法還很靈活,比如下面幾種都是合法的。a.基於 myArray 的所有元素建立數組切片:mySlice = myArray[:]b.基於 myArray 的前5個元素建立數組切片:mySlice = myArray[:5]c.基於從第5個元素開始的所有元素建立數組切片:mySlice = myArray[5:](2)通過make()函數直接建立數組切片建立一個初始元素個數為5的數組切片,元素初始值為0:mySlice1 := make([]int,5)建立一個初始元素個數為5的數組切片,元素初始值為0,並預留10個元素的儲存空間:mySlice2 := make([]int,5,10) 通過cap()函數可以擷取切片的分配空間,len()函數可以知道當前已儲存的元素個數.
fmt.Println("len(mySlice2):", len(mySlice2))fmt.Println("cap(mySlice2):", cap(mySlice2))
//輸出結果:len(mySlice2): 5cap(mySlice2): 10
當然,事實上還會有一個匿名數組被建立出來,只是不需要我們來操心而已。(3)直接在聲明的時候並初始化mySlice3 := []int{8,9,10}(4)基於數組切片建立數組切片oldSlice := []int{1,2,3,4,5}newSlice := oldSlice[:3] //基於oldSlice的前3個元素建立

10.2數組切片的元素遍曆

運算元組的所有方法都適合數組切片,通過上面的代碼也可以看得出來共有2種方式:for迴圈遍曆,或者for迴圈結合range來操作

10.3數組切片元素的動態增減

與數組相比,數組切片多了一個儲存能力的概念,即元素個數和分配的空間可以是兩個不同的值,合理地設定儲存能力的值,可以大幅降低數組切片內部重新分配記憶體和搬送記憶體塊的頻率,從而大大提高程式效能。通過append()函數可以在切片後面追加元素,例如:mySlice = append(mySlice, 8, 9, 10) append()函數的第二個參數是個不定的參數,有點類似java中的可變參數,甚至可以追加1個數組切片mySlice2 := []int{8,9,10}mySlice = append(mySlice,mySlice2...) //注意:這3個...點不能省略,否則編譯失敗

10.4內容複寫

通過copy()函數,可以將一個數組切片複製到另一個數組切片中,如果2個的數組切片不一樣大,則會按其中較小的那個數組切片的元素個數進行複製.slice1 := []int{1,2,3,4,5}slice2 := []int{5,4,3}copy(slice2,slice1) //只會複製slice1的前3個元素到slice2中,slice2中的值被自動替換copy(slice1,slice2) //只會複製slice2的3個元素到slice1的前3個位置,該3個位置的值自動替換,其他的不變

11.map

在C++/Java中,map一般都以庫(導包)的方式提供,在C++/Java中, 而在Go中,使用map 不需要引入任何庫,並且用起來也更加方便。看下面的例子:
type PersonInfo struct{    ID string    Name string    Address string}func main(){    var personDB map[string] PersonInfo //聲明一個key=string,value=PersonInfo的map    personDB = make(map[string] PersonInfo) //通過make初始化    //往這個map裡插入幾條資料    personDB["0"] = PersonInfo{"12345","Tom","Room 203,..."}    personDB["1"] = PersonInfo{"1","Jack","Room 101,..."}    //....    //從這個map尋找鍵為12345的資訊    person, ok := personDB["0"] //如果尋找到,則ok=true,否則=false    if ok{        fmt.Println("Found person",person.Name,"with ID",person.ID)    }else{        fmt.Println("Did not find person")    }}
//運行結果:Found person Tom with ID 12345

11.1map的聲明

上面的例子如果看不懂的話沒關係,下面就介紹下map的使用map的聲明基本上沒有多餘的元素,形如:var 變數名 map[key的類型] value的類型 

11.2map的建立

(1)通過make()函數建立
var myMap map[int] stringmyMap = make(map[int]string) //也可以簡寫成一條語句: myMap := make(map[int]string)myMap[0] = "1" //賦值myMap[1] = "2"result,_ := myMap[0] //這裡用到了匿名變數fmt.Println("myMap[0]=",result)fmt.Println("myMap[1]=",myMap[1])
//運行結果:myMap[0]= 1myMap[1]= 2
通過make建立的時候,還可以指定其初始容量myMap2 := make(map[int]string,100)(2)方式2,通過{}賦值的方式建立
myMap3 := map[int]string{    0:"張三",    1:"李四",}fmt.Println("myMap3[0]=",myMap3[0])fmt.Println("myMap3[1]=",myMap3[1])
//運行結果:myMap3[0]= 張三myMap3[1]= 李四

11.3元素的刪除

通過delete()函數完成,形如:delete(map變數名,map的key)如果要刪除的元素沒有對應的key,則什麼都不發生,但是如果傳入的map變數的值是 nil ,該調用將導致程式拋出異常(panic)。

11.4元素的尋找

map通過key尋找,可以返回2個變數,第一個為對應key的值,第二個為是否尋找成功的bool,形如:
value,ok := map[key]if ok{    //找到了,處理value}else{    //未找到}
當然,如果你很確定該key一定能夠找到對應的值的話,那就可以直接使用一個變數來接收,例如:value := map[key]或者,第二個參數用匿名參數來接收,例如:value,_ := map[key]

11.5元素的遍曆

(1)使用for迴圈遍曆    
myMap := make(map[int]int)myMap[0] = 100myMap[1] = 101myMap[2] = 102for i:=0;i<len(myMap);i++ {    fmt.Println("key=",i," value=",myMap[i])}
運行結果:key= 0  value= 100key= 1  value= 101key= 2  value= 102
(2)使用for迴圈結合range關鍵字遍曆
myMap := map[int]int{    0 : 10,    1 : 20,    2 : 30,}for k,v := range myMap{    fmt.Println("key=",k," value=",v)}
運行結果:key= 0  value= 10key= 1  value= 20key= 2  value= 30

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.