Go中的binary包實現了簡單的數字與字節(jié)序列的轉換以及變長值的編解碼
創(chuàng)新互聯(lián)公司專注于臺江網站建設服務及定制,我們擁有豐富的企業(yè)做網站經驗。 熱誠為您提供臺江營銷型網站建設,臺江網站制作、臺江網頁設計、臺江網站官網定制、微信小程序服務,打造臺江網絡公司原創(chuàng)品牌,更為您提供臺江網站排名全網營銷落地服務。
package main
import ( "fmt" "bytes" "encoding/binary" ) func main(){ n := 0x12345678 bytesBuffer := bytes.NewBuffer([]byte{}) //BigEndian 大端順序存儲 LittleEndian小端順序存儲 binary.Write(bytesBuffer, binary.BigEndian, int32(n)) data:=bytesBuffer.Bytes() fmt.Printf("[0]: %#x addr:%#x\n",data[0],data[0]) fmt.Printf("[0]: %#x addr:%#x\n",data[1],data[1]) fmt.Printf("[0]: %#x addr:%#x\n",data[2],data[2]) fmt.Printf("[0]: %#x addr:%#x\n",data[3],data[3]) }
輸出
[0]: 0x12 addr:0xc042010248 [1]: 0x34 addr:0xc042010249 [2]: 0x56 addr:0xc04201024a [3]: 0x78 addr:0xc04201024b
也可以使用下面的方式
n := 0x12345678 var data []byte = make([]byte,4) //操作的都是無符號整型 binary.BigEndian.PutUint32(data,uint32(n))
可以使用下面的方式判斷當前系統(tǒng)的字節(jié)序類型
const INT_SIZE int = int(unsafe.Sizeof(0))
//判斷我們系統(tǒng)中的字節(jié)序類型 func systemEdian() { var i int = 0x1 bs := (*[INT_SIZE]byte)(unsafe.Pointer(i)) if bs[0] == 0 { fmt.Println("system edian is little endian") } else { fmt.Println("system edian is big endian") } }
包 utf-8 實現的功能和常量用于文章utf8編碼,包含runes和utf8字節(jié)序列的轉換功能.在unicode中,一個中文占兩個字節(jié),utf-8中一個中文占三個字節(jié),golang默認的編碼是utf-8編碼,因此默認一個中文占三個字節(jié),但是golang中的字符串底層實際上是一個byte數組.
Output:
RuneSelf該值的字節(jié)碼值為128,在判斷是否是常規(guī)的ascii碼是使用。hicb字節(jié)碼值為191. FF 的對應的字節(jié)碼為255。
計算字符串中的rune數量,原理:首先取出字符串的碼值,然后判斷是不是個小于128的,如果是小于則直接continue.rune個數++.
如果是個十六進制f1.的則是無效字符,直接continue.rune個數++,也就是說一個無效的字符也當成一個字長為1的rune.如果字符的碼值在first列表中的值和7按位的結果為其字長,比如上面示例中的 鋼 。其字長為三位,第一位的值為 233 .二進制形式為 11101001 ;與7按位與后的值為0.從acceptRanges中取出的結果為{locb, hicb}。也就是標識 ox80 到 0xbf 之間的值。而結果n也就是直接size+3跳過3個字節(jié)后,rune個數++。其他函數的處理流程差不多,不再過多敘述。
示例:
ValidString返回值表明參數字符串是否是一個合法的可utf8編碼的字符串。
RuneCount返回參數中包含的rune數量,第一個例子中將 utf8.RuneCountInString ,改成該方法調用,返回的結果相同。錯誤的和短的被當成一個長一字節(jié)的rune.單個字符 H 就表示一個長度為1字節(jié)的rune.
該函數標識參數是否以一個可編碼的rune開頭,上面的例子中,因為字符串是以一個ascii碼值在0-127內的字符開頭,所以在執(zhí)行
first[p[0]] 時,取到的是 p[0] 是72,在first列表中,127之前的值都相同都為 0xF0 ,十進制標識為240,與7按位與后值為0,所以,直接返回 true .
和FullRune類似,只是參數為字符串形式
首先說一下go中的字符串類型:
字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個字節(jié)連接起來的。Go語言的字符串的字節(jié)使用UTF-8編碼標識Unicode文本。
下面介紹字符串的三種遍歷方式,根據實際情況選擇即可。
該遍歷方式==缺點==:遍歷是按照字節(jié)遍歷,因此如果有中文等非英文字符,就會出現亂碼,比如要遍歷"abc北京"這個字符串,效果如下:
可見這不是我們想要的效果,根據utf-8中文編碼規(guī)則,我們要str[3]str[4]str[5]三個字節(jié)合起來組成“北”字及 str[6]str[7]str[8]合起來組成“京”字。由此引出下面第二種遍歷方法。
該方式是按照字符遍歷的,所以不會出現亂碼,如下:
運行結果:
從圖中可以看到第二個漢子“京”的開始下標是6,直接跳過了4和5,可見確實依照utf8編碼方式將三個字節(jié)組合成了一個漢字,str[3]-str[5]組合成“北”字,str[6]-str[8]組合成了“京”字。
由于下標的不確定性,所以引出了下面的遍歷方式。
1 可以先將字符串轉成 []rune 切片
2 再用常規(guī)方法進行遍歷
運行效果:
由此可見下標是按1遞增的,沒有產生跳躍現象。
Go語言標準庫中提供了sort包對整型,浮點型,字符串型切片進行排序,檢查一個切片是否排好序,使用二分法搜索函數在一個有序切片中搜索一個元素等功能。
關于sort包內的函數說明與使用,請查看
在這里簡單講幾個sort包中常用的函數
在Go語言中,對字符串的排序都是按照字節(jié)排序,也就是說在對字符串排序時是區(qū)分大小寫的。
二分搜索算法
Go語言中提供了一個使用二分搜索算法的sort.Search(size,fn)方法:每次只需要比較㏒?n個元素,其中n為切片中元素的總數。
sort.Search(size,fn)函數接受兩個參數:所處理的切片的長度和一個將目標元素與有序切片的元素相比較的函數,該函數是一個閉包,如果該有序切片是升序排列,那么在判斷時使用 有序切片的元素 = 目標元素。該函數返回一個int值,表示與目標元素相同的切片元素的索引。
在切片中查找出某個與目標字符串相同的元素索引
Buffer 介紹
Buffer 是 bytes 包中的一個 type Buffer struct{…}
A buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use.
(是一個變長的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一個 空的 buffer,但是可以使用)
Buffer 就像一個集裝箱容器,可以存東西,取東西(存取數據)
創(chuàng)建緩沖器
輸出
寫入到緩沖器
buffer在new的時候是空的,也是可以直接Write的
Write
結果
WriteString
結果
WriteByte
WriteRune
結果
從緩沖器中寫出
讀出緩沖器
Read
ReadByte
返回緩沖器頭部的第一個byte
ReadRun
ReadRune方法,返回緩沖器頭部的第一個rune
為什么n==3,而n1==1呢?我們看下ReadRune 的源碼
ReadBytes
ReadBytes方法,需要一個byte作為分隔符,讀的時候從緩沖器里找出第一個出現的分隔符,緩沖器頭部開始到分隔符之間的byte返回。
相當于有一個分隔符
ReadString
和readBytes方法類似
讀入緩沖器
ReadFrom方法,從一個實現io.Reader接口的r,把r的內容讀到緩沖器里,n返回讀的數量
從緩沖器取出
Next方法,返回前n個byte(slice),原緩沖器變
緩沖區(qū)原理介紹
go字節(jié)緩沖區(qū)底層以字節(jié)切片做存儲,切片存在長度len與容量cap, 緩沖區(qū)寫從長度len的位置開始寫,當lencap時,會自動擴容。緩沖區(qū)讀會從內置標記off位置開始讀(off始終記錄讀的起始位置),當off==len時,表明緩沖區(qū)已全部讀完
并重置緩沖區(qū)(len=off=0),此外當將要內容長度+已寫的長度(即len) = cap/2時,緩沖區(qū)前移覆蓋掉已讀的內容(off=0,len-=off),從避免緩沖區(qū)不斷擴容
int is a signed integer type that is at least 32 bits in size. It is a distinct type, however, and not an alias for, say, int32.
int 是帶符號整數類型,其大小至少為32位。 它是一種確切的類型,而不是 int32 的別名。
int 不是int32,那 int 在內存站多少字節(jié)呢?官方沒有明確,讓我們測試下。
GOARCH="amd64"
package main
import (
"fmt"
"unsafe"
)
func main() {
i := int(1)
fmt.Println(unsafe.Sizeof(i)) // 4
j := 1
fmt.Println(unsafe.Sizeof(j)) // 4
u := uint(1)
fmt.Println(unsafe.Sizeof(u)) // 4
}
可以認為 int 是4字節(jié)么?我不敢這樣認為,GoLang支持多種平臺架構。如果對size有明確要求,那就用 int32 之類的吧。
補充:隨Go版本的變化,這個的確是在變化,所以到底占用多少字節(jié),還是看具體版本吧