go強制類型轉換type(a)以及范圍引起的數(shù)據(jù)差異
一、介紹
golang中的類型轉換分強制類型轉換和類型斷言普通變量類型int,float,string 都可以使用type(a)這種形式來進行強制類型轉換
二、數(shù)字的類型轉換int和float
1、整數(shù)類型 int
func TestInt(t *testing.T) { var i int = -1 var i8 int8 = int8(i) var i16 int16 = int16(i) var i32 int32 = int32(i) var i64 int64 = int64(i) t.Log(i, i8, i16, i32, i64) //-1 -1 -1 -1 -1 var n int = 1111111 var n8 int8 = int8(n) var n16 int16 = int16(n) var n32 int32 = int32(n) var n64 int64 = int64(n) t.Log(n, n8, n16, n32, n64) //1111111 71 -3001 1111111 1111111 }
我們發(fā)現(xiàn)當 在轉換n的過程中,轉成int8和int16的時候,出現(xiàn)了錯誤,為什么會這樣?
在于int類型在mac上是默認的64個bit,
int8 表示 -128 到 127 之間的整數(shù)值 (8個bit)
int16 表示 -32768 和 32767 之間的整數(shù)值 (16個bit)
他們之間能夠存儲的范圍是不相同的,如果超過了某個類型的范圍就會出錯。
2、正整數(shù)類型 uint
func TestUint(t *testing.T) { var i uint = 1 var i8 uint8 = uint8(i) var i16 uint16 = uint16(i) var i32 uint32 = uint32(i) var i64 uint64 = uint64(i) t.Log(i, i8, i16, i32, i64) //1 1 1 1 1 var u uint = 1111111 var u8 uint8 = uint8(u) var u16 uint16 = uint16(u) var u32 uint32 = uint32(u) var u64 uint64 = uint64(u) t.Log(u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111 }
在類型范圍內的數(shù)據(jù)轉換正確,范圍外的轉換錯誤。
3、int和uint之間的強制轉換
func TestInt2(t *testing.T) { var i int = -1 var i8 uint8 = uint8(i) var i16 uint16 = uint16(i) var i32 uint32 = uint32(i) var i64 uint64 = uint64(i) t.Log(i, i8, i16, i32, i64) //-1 255 65535 4294967295 18446744073709551615 var n int = 1 var n8 uint8 = uint8(n) var n16 uint16 = uint16(n) var n32 uint32 = uint32(n) var n64 uint64 = uint64(n) t.Log(n, n8, n16, n32, n64) //1 1 1 1 1 var u int = 1111111 var u8 uint8 = uint8(u) var u16 uint16 = uint16(u) var u32 uint32 = uint32(u) var u64 uint64 = uint64(u) t.Log(u, u8, u16, u32, u64) //1111111 71 62535 1111111 1111111 }
我們發(fā)現(xiàn)當每種類型范圍不一樣的話,轉換不留神還是會有很大的錯誤。
4、float32和float64的強制轉換
func TestFloat(t *testing.T) { var f32 float32 = 333.333 var f64 float64 = float64(f32) t.Log(f32, f64) //333.333 333.3330078125 //都在各自的范圍內 var fl64 float64 = 333.333 var fl32 float32 = float32(fl64) t.Log(fl64, fl32) //333.333 333.333 //大類型的范圍 超過小的類型范圍 var flo64 float64 = 33333333333333333.333 var flo32 float32 = float32(flo64) t.Log(flo64, flo32) //333.333 333.333 }
首先我們判斷float32和float64有什么不同,因為使用內存大小不一樣,導致精度以及范圍的不同。
- float32和float64互相轉化,因為精度不一樣,導致數(shù)據(jù)差異
- float32和float64互相轉化,因為范圍不一樣,導致數(shù)據(jù)差異
5、float和int互相轉換
func TestFloatInt(t *testing.T) { var i int = 333 var f32 float32 = float32(i) var f64 float64 = float64(i) t.Log(i, f32, f64) //333 333 333 var f float32 = 333.3 var n int = int(f) var n8 int8 = int8(f) var n16 int16 = int16(f) var n32 int32 = int32(f) var n64 int64 = int64(f) t.Log(f, n, n8, n16, n32, n64) //333.3 333 77 333 333 333 }
因為是mac系統(tǒng),我這里int是有符號64位整數(shù)數(shù)據(jù)類型。
類型 | 比特數(shù) | 有效數(shù)字 | 數(shù)值范圍 |
---|---|---|---|
int64 | 64 | -2^63 ( -9,223,372,036,854,775,808) | 2^63-1(+9,223,372,036,854,775,807 ) |
float32 | 32 | 6-7 | -3.410(-38)~3.410(38) |
float64 | 64 | 15-16 | -1.710(-308)~1.710(308) |
基本上當int轉成float類型只要在范圍內的就沒有啥問題
而float轉成int的時候,需要考慮,小數(shù)點后面的會自動的舍去,以及范圍問題。
三、指針unsafe.Pointer任意類型與具體指針類型的轉換
注意,指針unsafe.Pointer任意類型,只能轉成 具體類型的指針類型
如轉成int類型的指針類型 *int
強制準換的語法為 type(a),那么就是這里(*int)(a),而不是int(a)!
1、指針unsafe.Pointer轉成int指針類型
func TestIntPointer(t *testing.T) { //范圍內可以正確轉化的情況 var i int = 100 pi := unsafe.Pointer(&i) //轉成int相關類型 var n *int = (*int)(pi) var n8 *int8 = (*int8)(pi) var n16 *int16 = (*int16)(pi) var n32 *int32 = (*int32)(pi) var n64 *int64 = (*int64)(pi) t.Log(*n, *n8, *n16, *n32, *n64)//100 100 100 100 100 //-------------------------- //范圍超出的情況 var i2 int = 10000 pi2 := unsafe.Pointer(&i2) //轉成int相關類型 var nn *int = (*int)(pi2) var nn8 *int8 = (*int8)(pi2) var nn16 *int16 = (*int16)(pi2) var nn32 *int32 = (*int32)(pi2) var nn64 *int64 = (*int64)(pi2) t.Log(*nn, *nn8, *nn16, *nn32, *nn64)//10000 16 10000 10000 10000 }
這里雖然是指針了,但還是需要注意具體類型的范圍。
不然超出類型的最大或者最小值,仍然是錯誤的。
2、指針unsafe.Pointer轉成struct指針類型
還是type(a)的方式,這里的a變量為 unsafe.Pointer(&a)
type為 (*Struct)
完整的表達式為 (*Struct)(unsafe.Pointer(&a))
func TestStruct(t *testing.T) { //有一個struct結構體S,里面width和height兩個int類型 type S struct { wight int height int } s := S{ wight: 5, height: 6, } p := unsafe.Pointer(&s) //{5 6} t.Log(s) //測試轉成為T,T里面有w和h兩個int類型 type T struct { w int h int } st := (*T)(p) t.Log(*st) //{5 6} }
發(fā)現(xiàn)雖然S和T兩個結構體不一樣,但卻轉成了正確的值,為什么?
因為指針關注的內存控股,不管是S里的wight或者T里面的w,其實都是int類型,占用了相同的內存
所以能夠正確的解析出來
如果此時我們把 T的類型改一下成int8試試,就會發(fā)現(xiàn)錯誤
func TestStruct(t *testing.T) { //有一個struct結構體S,里面width和height兩個int類型 type S struct { wight int height int } s := S{ wight: 5, height: 6, } p := unsafe.Pointer(&s) //{5 6} t.Log(s) //測試轉成為T,T里面有w和h兩個int8類型 type T struct { w int8 h int8 } st := (*T)(p) t.Log(*st) //{5 0} }
第一個獲取的5值,是因為在指針的0偏移量所以能夠獲取到,也正好在范圍內,如果S.wight=10000
那么第一個也會錯誤,如下
func TestStruct(t *testing.T) { //有一個struct結構體S,里面width和height兩個int類型 type S struct { wight int height int } s := S{ wight: 10000, height: 6, } p := unsafe.Pointer(&s) //{10000 6} t.Log(s) //測試轉成為T,T里面有w和h兩個int8類型 type T struct { w int8 h int8 } st := (*T)(p) t.Log(*st) //{16 39} }
所以我們可以得出如果是指針類型的話,只要里面的指針是一樣的,才能強制轉換成正確的值。
以上就是go強制類型轉換type(a)以及范圍引起的數(shù)據(jù)差異的詳細內容,更多關于go強制類型轉換type數(shù)據(jù)差異的資料請關注腳本之家其它相關文章!
相關文章
Golang RSA生成密鑰、加密、解密、簽名與驗簽的實現(xiàn)
RSA 是最常用的非對稱加密算法,本文主要介紹了Golang RSA生成密鑰、加密、解密、簽名與驗簽的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2023-11-11深入分析Go?實現(xiàn)?MySQL?數(shù)據(jù)庫事務
本文深入分析了Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務的原理和實現(xiàn)方式,包括事務的ACID特性、事務的隔離級別、事務的實現(xiàn)方式等。同時,本文還介紹了Go語言中的事務處理機制和相關的API函數(shù),以及如何使用Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務。2023-06-06go語言中數(shù)據(jù)接口set集合的實現(xiàn)
set集合是一種常見的數(shù)據(jù)結構,它代表了一個唯一元素的集合,本文主要介紹了set的基本特性,包括唯一性、無序性、可變性和集合運算,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-10-10