Golang語言社群--Go語言基礎第四節型別
大家好,我是Golang語言社群主編彬哥,這節給大家講解Go語言中的型別。
Go語言中使用的型別包括:
基礎型別 | ||
---|---|---|
布林型別(bool) |
var b1 bool = true |
|
整型 |
var v1 int = 12 |
|
浮點型別(float32、float64) |
var f1 float32 = 12.0 |
|
複數型別(complex64、complex128) |
var c1 complex64 = 3.2 + 12i |
|
字串(string) |
var s string = “sina” |
|
字元型別(rune) |
代表單個的unicode字元 |
|
錯誤型別(error) |
||
複合型別 | ||
指標(pointer) |
||
陣列(array) |
[32] byte |
|
切片(slice) |
||
字典(map) |
var word_count map[string] int |
|
通道(chan) |
用於協程間通訊 |
|
結構體(struct) |
||
介面(interface) |
1、布林型別
布林型別不能接受其它型別的賦值,不支援自動或強制的型別轉換,以下的示例是一些錯誤的用法:
var golang bool
golang = 1 // 錯誤
golang = bool(1) // 錯誤
以下的用法是正確的:
var golang bool golang = (1!=0)
2、整型
型別 |
長度 |
值範圍 |
---|---|---|
int8 |
1 |
-128 ~ 127 |
uint8(即byte) |
1 |
0 ~ 255 |
int16 |
2 |
-32768 ~ 32767 |
uint16 |
2 |
0 ~ 65535 |
int32 |
4 |
-2147483648 ~ 2147483647 |
uint32 |
4 |
0 ~ 4294967295 |
int64 |
8 |
(-2^63) ~ (2^63-1) |
uint64 |
8 |
0 ~ (2^64-1) |
int |
平臺相關 |
平臺相關 |
uint |
平臺相關 |
平臺相關 |
uintptr |
同指針 |
32位平臺下為4位元組,64位平臺下為8位元組 |
需要注意的是,int和int32是不同的型別, 不能相互賦值,例如:
var val2 int32
val1 := 64 // val1會被自動推導為int型別
var2 = val1 // error
var2 = int32(val1) // ok
此外,不同型別的整型數不能直接比較,比如int8型別的數和int型別的數不能直接比較,但各種型別的整型變數都可以直接與字面常量(literal)進行比較,比如:
var i int32
var j int64
i,j = 1,2
if i==j { // error
fmt.Println("i and j are equal.")
}
if i==1 || j==2 { // ok
fmt.Println("i and j are equal.")
}
3、浮點型
Go語言中的float32和float64分別等價於C語言的float、double型別;
var i float32 = 12.1
j := 64.0 // 自動推導為float64型別
j = i // error
j = float64(i) // ok
判斷兩個浮點數是否相等,是根據不同精度來的:
import "math"
func IsEqual(f1, f2, p float64) bool {
return math.Fdim(f1, f2) < p
}
其中,p是使用者自定義的比較精度,比如p=0.00001。
4、字元型別
在Go語言中支援兩個字元型別,一個是byte(實際上是uint8的別名),代表UTF-8字串的單個位元組的值;另一個是rune,代表單個Unicode字元。
關於rune相關的操作,可查閱Go標準庫的unicode包;另外unicode/utf8包也提供了UTF8和Unicode之間的轉換。
5、字串
字串支援下標讀取操作:
str := "Hello world"
ch := str[0]
fmt.Printf("The length of "%s" is %dn", str, len(str))
fmt.Printf("The 1st character of "%s" is '%c'n", str, ch)
但字串的內容在初始化後不能被修改,例如:
str := "Hello world"
str[0] = 'X' // error
常用的字串操作:
操作 |
含義 |
---|---|
s1 + s2 |
字串連線 |
len(s) |
字串長度 |
s[i] |
取字元 |
字串遍歷有兩種方式:
str := "Hello,世界"
// 以位元組陣列的方式遍歷
for i := 0; i<len(str); i++ {
ch := str[i]
fmt.Println(i, ch)
}
// 以unicode字元方式遍歷,每個字元的型別是rune
for i, ch := range str {
fmt.Println(i, ch)
}
6、陣列
陣列的宣告方法比較多,比如:
[32] byte // 位元組陣列
[2*N] struct {x, y int 32} // 結構體陣列
[1000] *float64 // 指標陣列
[3][5] int // 二維陣列
[2][2][2] float64
在宣告陣列時長度可以為一個常量或一個常量表達式,陣列長度在定義以後就不可以再改變。
陣列支援按下標讀寫元素,也支援range關鍵字的遍歷,例如:
var array = [5] int {10,20,30,40,50}
for i, v := range array {
array[i] = v*2;
}
for i, v := range array {
fmt.Println(i, v)
}
另外,陣列是值型別,如果將陣列作為函式引數傳遞,則在函式呼叫的時候該引數將發生資料複製,因此,在函式體中無法修改傳入的陣列的內容。
7、slice
陣列切片的資料結構可以抽象為以下3個變數:
- 一個指向原生陣列的指標;
- 陣列切片中的元素個數;
- 陣列切片已分配的儲存空間;
陣列切片類似於C++中STL的std::vector<>,支援動態擴充套件陣列,並且可以被作為函式引數傳遞而不會導致元素被複制。
建立陣列切片有下面多種方式:
1、基於陣列建立的方式
var myArray [10] int = [10] int {1,2,3,4,5,6,7,8,9,10}
var s1 = myArray[:] // 基於myArray的所有元素建立陣列切片
var s2 = myArray[:5] // 基於myArray的前5個元素建立陣列切片
var s3 = myArray[5:] // 基於myArray從第5個元素開始的所有元素建立陣列切片
2、直接建立陣列切片的方式
s1 := make([] int,5) // 建立一個初始元素個數為5的陣列切片,元素初始值為0
s2 := make([] int,5, 10) // 建立一個初始元素個數為5的陣列切片,元素初始值為0,並預留10個元素的儲存空間
s3 := []int{1,2,3,4,5} // 建立並初始化包含5個指定元素的陣列切片
3、基於陣列切片建立的方式
oldSlice := []int{1,2,3,4,5}
newSlice := oldSlice[:3]
運算元組元素的所有方法都適用於陣列切片,比如陣列切片也可以按下標讀寫元素,用len()獲取元素個數,並支援使用range關鍵字來快速遍歷所有元素。
陣列切片支援可動態增減元素,內建的cap()和len()函式,分別返回陣列切片分配的空間大小、當前儲存的元素個數。
s := make([] int,5, 10)
fmt.Println("len(s)=",len(s)) // 5
fmt.Println("cap(s)=",cap(s)) // 10
使用append函式可以在陣列切片尾端新增新元素:
s = append(s, 1,2,3)
如果追加的內容長度超過當前已分配的儲存空間(即cap()返回值),陣列切片會自動分配一塊足夠大的記憶體。
還可以將另一個數組切片追加到一個數組切片末端:
s2 := []int{8,9,10}
s = append(s, s2...) // s2後面的省略號必須要有
陣列切片的複製,如果兩個slice不一樣大,就會按其中較小的slice的元素個數進行復制,例如:
s1 := []int {1,2,3,4,5}
s2 := []int {5,4,7}
copy(s1, s2) //只複製s2的3個元素到s1的前3個位置
copy(s2, s1) //只複製s1的前3個元素到s2中
8、map
map是key-value結構的一個字典,類似於C++中STL的std::map<>。
例子:
type PersonInfo struct {
ID string
Name string
Address string
}
func main() {
var personDB map[string] PersonInfo // 變數宣告
personDB = make(map[string] PersonInfo) // 變數建立
personDB["1"] = PersonInfo{"12345","Tom","Room 203"} // 增加了一個鍵
person, ok := personDB["1"] // 查詢
if ok {
fmt.Println("found person", person.Name, "with ID 1")
} else {
fmt.Println("Did not find person with ID 1")
}
delete(personDB, "1") // 刪除一個鍵
}