[TOC] # 本篇前瞻 歡迎來go語言的基礎篇,這裡會幫你梳理一下go語言的基本類型,註意本篇有參考[go聖經](https://gopl-zh.github.io/),如果你有完整學習的需求可以看一下。另外,go語言的基本類型比較簡單,介紹過程就比較粗暴,不過我們需要先從一個例題開始。 # Le ...
目錄
本篇前瞻
歡迎來go語言的基礎篇,這裡會幫你梳理一下go語言的基本類型,註意本篇有參考go聖經,如果你有完整學習的需求可以看一下。另外,go語言的基本類型比較簡單,介紹過程就比較粗暴,不過我們需要先從一個例題開始。
Leetcode習題9
先讓我們看下這個來自leetcode的例子,這個是一個比較好的例子,裡面有一些關於整形的的知識
題目描述
給你一個整數 x
,如果 x
是一個迴文整數,返回 true
;否則,返回 false
。
迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
原題解析
註意原題中已經提供了一個go語言的函數
func isPalindrome(x int) bool {
}
為了方便我們編寫代碼,我們只需要知道這個函數的輸入是x
,輸出是代表是否是迴文數(是:true,否:false
),return
能返回輸出。
解題方法:
-
負數必然不是迴文數。
-
對於非負整數,我們迴圈
x除10
,通過x%10
獲得最低位,並且把最低位當作最高位加入到px
中,得到了x
的反轉過來的數px
-
判斷
px
和x
是否相等就可以了。
代碼編寫
使用int32
來計算px
, 將如下代碼提交,不行,答案錯誤,這是因為如果x=2147483647
,那麼px=7463847412
,超出int32
的範圍了
func isPalindrome(x int) bool {
if x < 0 {
return false
}
x32 := int32(x)
px32 := int32(x)
for x32 != 0 {
px32 = px32*10 + x32%10
x32 /= 10
}
return px32 == int32(x)
}
那麼換成int64
代碼如下,提交通過了,我們花費了28ms
,僅僅擊敗12%
的人,時間上有問題嗎?
func isPalindrome(x int) bool {
if (x < 0) {
return false
}
x64 := int64(x)
px64 := int64(0)
for x64 != 0 {
px64 = px64*10 + x64%10
x64 /= 10
}
return px64 == int64(x)
}
現在嘗試去掉int64
的強制轉化,居然通過了,只花費4ms
,擊敗了97%
的人,這不可思議!
func isPalindrome(x int) bool {
if (x < 0) {
return false
}
x64 := x //整形
px64 := 0
for x64 != 0 {
px64 = px64*10 + x64%10
x64 /= 10
}
return px64 == x //布爾型
}
有符號整形
這種整形就是可以表示負整數,0和正整數
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
int8 | 8 | 1 | -2^7 ~ 2^7-1(-128~127) |
int16 | 16 | 2 | -2^15 ~ 2^15-1(-32768 ~ 32767) |
int32 | 32 | 4 | -2^32 ~ 2^32-1(-2147483648 ~ 2147483647) |
int64 | 64 | 8 | -2^64 ~ 2^64-1(-9223372036854775808 ~ 9223372036854775807) |
int | 32或64 | 4或8 | 同int32或int64 |
註意:int的占用空間取決於你的操作系統是32位或64位
那麼利用這三次提交的結果,並結合有符號整形的知識,我們可以得出:
- 變數強制類型轉化會耗時
- 編程中的變數的取值範圍很重要
- Leetcode的判題系統是64位的
基本數據類型
從上面的例題中我們能發現數據類型的選擇在編程過程中有著決定性的作用,雖然這很基礎,但是決定了你的編程結果是否正確,選擇合適的類型會使你編寫的程式運行速度更快,占用記憶體更小。
註意:由於複數類型
不常用的關係,本章節不會介紹該類型。
整形
這個不是南韓的“絕學”——整形術,整形在編程中可以表示一定範圍內的整數
註意:int或uint的占用空間取決於你的操作系統是32位或64位
對於整形我們要關註的是數據類型的長度,數據範圍
代碼如下:
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
fmt.Printf("int8 length: %v range: %v ~ %v\n", unsafe.Sizeof(int8(1)), math.MinInt8, math.MaxInt8)
fmt.Printf("int16 length: %v range: %v ~ %v\n", unsafe.Sizeof(int16(1)), math.MinInt16, math.MaxInt16)
fmt.Printf("int32 length: %v range: %v ~ %v\n", unsafe.Sizeof(int32(1)), math.MinInt32, math.MaxInt32)
fmt.Printf("int64 length: %v range: %v ~ %v\n", unsafe.Sizeof(int64(1)), math.MinInt64, math.MaxInt64)
fmt.Printf("int length: %v\n", unsafe.Sizeof(int(1)))
fmt.Printf("uint8 length: %v range: 0 ~ %v\n", unsafe.Sizeof(uint8(1)), math.MaxUint8)
fmt.Printf("uint16 length: %v range: 0 ~ %v\n", unsafe.Sizeof(uint16(1)), math.MaxUint16)
fmt.Printf("uint32 length: %v range: 0 ~ %v\n", unsafe.Sizeof(uint32(1)), math.MaxUint32)
fmt.Printf("uint64 length: %v range: 0 ~ %v\n", unsafe.Sizeof(uint64(1)), uint64(math.MaxUint64))
fmt.Printf("uint length: %v\n", unsafe.Sizeof(uint(1)))
}
輸出:
int8 length: 1 range: -128 ~ 127
int16 length: 2 range: -32768 ~ 32767
int32 length: 4 range: -2147483648 ~ 2147483647
int64 length: 8 range: -9223372036854775808 ~ 9223372036854775807
int length: 8
uint8 length: 1 range: 0 ~ 255
uint16 length: 2 range: 0 ~ 65535
uint32 length: 4 range: 0 ~ 4294967295
uint64 length: 8 range: 0 ~ 18446744073709551615
uint length: 8
有符號整形
這種整形就是可以表示負整數,0和正整數
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
int8 | 8 | 1 | -2^7 ~ 2^7-1(-128~127) |
int16 | 16 | 2 | -2^15 ~ 2^15-1(-32768 ~ 32767) |
int32 | 32 | 4 | -2^32 ~ 2^32-1(-2147483648 ~ 2147483647) |
int64 | 64 | 8 | -2^64 ~ 2^64-1(-9223372036854775808 ~ 9223372036854775807) |
int | 32或64 | 4或8 | 同int32或int64 |
無符號整形
這種整形就是可以表示非負整數
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
uint8 | 8 | 1 | 0 ~ 2^8-1(0 ~ 255) |
uint16 | 16 | 2 | 0 ~ 2^16-1(0 ~ 65535) |
uint32 | 32 | 4 | 0 ~ 2^32-1(0 ~ 4294967295) |
uint64 | 64 | 8 | 0 ~ 2^64-1(0 ~ 18446744073709551615) |
uint | 32或64 | 4或8 | 同uint32或uint64 |
浮點型
浮點型在編程中可以表示一定範圍內的實數
註意:對於浮點型我們要關註的是數據類型的長度,數據範圍,但更要關註精度。
代碼如下:
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
fmt.Printf("float32 length: %v range: %v ~ %v\n", unsafe.Sizeof(float32(1)), -math.MaxFloat32, math.MaxFloat32)
fmt.Printf("float64 length: %v range: %v ~ %v\n", unsafe.Sizeof(float64(1)), -math.MaxFloat64, math.MaxFloat64)
fmt.Printf("after transfer float32 %v\n", float32(1.328))
fmt.Printf("after transfer float64 %v\n", float64(float32(1.328)))
}
輸出:
float32 length: 4 range: -3.4028234663852886e+38 ~ 3.4028234663852886e+38
float64 length: 8 range: -1.7976931348623157e+308 ~ 1.7976931348623157e+308
before transfer float32: 1.328
after transfer float64: 1.3279999494552612
你可以看到1.328在float32強制轉化為float64反常地失去了一些精度,當然這就是為啥項目和資料庫只有高精度實數的原因,你可以想象在這種情況時使用乘法後可怕的結果。
至於這個產生的原因時浮點32型和浮點64型在電腦上表示方式不同,這部分內容你可以查看《電腦程式的構造和解釋》。
列表如下:
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
float32 | 32 | 4 | -3.4028234663852886e+38 ~ 3.4028234663852886e+38 |
float64 | 64 | 8 | -1.7976931348623157e+308 ~ 1.7976931348623157e+308 |
布爾型
最簡單的類型
註意:分支語句中的if後面的表達式的結果值是true或false
代碼如下:
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Printf("bool length: %v %v/%v", unsafe.Sizeof(true), 0 == 0, 0 != 0)
}
輸出:
bool length: 1 true/false
列表如下:
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
bool | 1 | 1 | true/false |
字元
註意:byte是包含ascii碼,即uint8 ,rune是可以包含utf-8的,即uint32
代碼如下:
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Printf("byte length: %v %v %c\n", unsafe.Sizeof(byte('a')),byte('a'),byte('a'))
fmt.Printf("rune length: %v %v %c\n", unsafe.Sizeof(rune('中')),rune('中'),rune('中'))
}
輸出:
byte length: 1 97 a
rune length: 4 20013 中
列表如下:
數據類型 | 占用空間(bit) | 長度(位元組) | 取值範圍 |
---|---|---|---|
byte | 8 | 1 | 0 ~ 2^8-1(0 ~ 255) |
rune | 32 | 4 | 0 ~ 2^32-1(0 ~ 4294967295) |
本篇小結
很好,你已經閱讀完了go的基本數據類型!看是不是簡單?學習go語言其實比較簡單,你先通過例題知道了選擇基礎數據類型的重要性,然後通過基本數據類型,你知道了每個類型都有自己的長度,取值範圍和註意點,最後相關代碼房子在go語言學習的go-base/2中,你需要編寫這些代碼來實踐一下go語言。
下一篇預告
go語言的控制結構