go基礎(chǔ)——字節(jié)

內(nèi)容

  • 1 byte/rune
  • 2 bit基本操作
  • 3 字節(jié)序
  • 4 一個(gè)bit使用例子——bitmap

一 byte/rune

  • 編碼: 編碼就是人類語(yǔ)言字符和存儲(chǔ)中計(jì)算機(jī)中的字節(jié)的一種映射表泛烙,最開始是用ascii編碼表就可以表示完所有的英文字符,但是沒法表示其他語(yǔ)言字符贬丛,所以誕生了unicode版扩、utf-8等不同的編碼表旦部;go中用byte和rune類型來代表ascii字符和unicode字符塞弊;
  • byte和uint8是等價(jià)的蔫缸,通常處理ascii字符惋鸥,因?yàn)橹挥?位來存儲(chǔ)猬腰,實(shí)際只可以存儲(chǔ)256個(gè)字符鸟废,所以有了unicode、utf-8等編碼來處理其他復(fù)雜字符
  • go中的rune是int32的一個(gè)別名姑荷,占用4個(gè)字節(jié)存儲(chǔ)盒延,一個(gè)rune就是一個(gè)unicode字符,當(dāng)代碼中要處理中文鼠冕、日文等字符時(shí)添寺,通常使用rune來處理。
    所以在一些場(chǎng)景就要特別注意:
 1 計(jì)算中文字符串長(zhǎng)度不用直接用len, 字符串的實(shí)現(xiàn)是一個(gè)byte[], len求的是字節(jié)數(shù)組的長(zhǎng)度懈费,s3在存儲(chǔ)時(shí)實(shí)際是存儲(chǔ)成一個(gè)字節(jié)數(shù)組计露,共6個(gè)字節(jié),代替應(yīng)該用utf8.RuneCountInString()來統(tǒng)計(jì)長(zhǎng)度楞捂,應(yīng)該統(tǒng)計(jì)中文字符unicode編碼后的rune長(zhǎng)度才合適
    
    s := '中' // 用單引號(hào)代表一個(gè)字符薄坏,要和雙引號(hào)區(qū)別面徽,注意和python里區(qū)別
    var s2 byte = 'a'
    s3 := "中國(guó)"
    fmt.Println(unsafe.Sizeof(s))
    fmt.Println(unsafe.Sizeof(s2))
    fmt.Println(len(s3))
    fmt.Println(utf8.RuneCountInString(s3))
輸出:
4
1
6
2

補(bǔ)充:
1個(gè)字節(jié)byte(8位2進(jìn)制數(shù))戴卜,可以用來表示1個(gè)[0-255]之間的10進(jìn)制數(shù),可以用來表示2個(gè)16進(jìn)制數(shù)(每四位二進(jìn)制可以表示1個(gè)16進(jìn)制數(shù)), 16進(jìn)制數(shù)以0x開頭叔壤,0xff轉(zhuǎn)換二級(jí)制是1111111繁堡,所以有些代碼里經(jīng)成蛏疲看到0xff,0xff等價(jià)于11111111椭蹄,使用0xff看起來更加直觀,簡(jiǎn)潔

二 bit基本操作

  • 將字節(jié)中某位設(shè)置為1
將240第四位設(shè)置為1闻牡,步驟:1先左移3位,得到1000绳矩; 然后與原來值或運(yùn)算
    a := uint8(240)
    fmt.Printf("%b\n", a)
    a = a | (1 << 3)
    fmt.Printf("%b\n", a)
輸出:
11110000
11111000
  • 將某一位設(shè)置為0
將第7位設(shè)置為0罩润, 步驟:1左移6位,然后取反翼馆,然后與運(yùn)算
    a := uint8(240)
    fmt.Printf("%b\n", a)
    a = a&^(1 << 6)
    fmt.Printf("%b\n", a)
輸出:
11110000
10110000
  • 獲取某一位的值
獲取第5位的值:先將左移兩位割以,將第5位的值頂?shù)阶铐敹耍缓笤谟乙?位应媚,將第5位的值移到最右端严沥,邊得到第5位的值,如果是uint16 uint32的則相應(yīng)的根據(jù)類型總位數(shù)計(jì)算一下中姜,類似uint8 8位的計(jì)算
    a := uint8(240)
    fmt.Printf("%b\n", a)
    a = (a<<2)>>7
    fmt.Printf("%b\n", a)
輸出:
11110000
1

三 字節(jié)序

字節(jié)序通俗來說消玄,就是多字節(jié)數(shù)據(jù)類型在內(nèi)存中的存放順序,有兩種順序:

  • 大端序:數(shù)值的低位存放在地址的高位,高位存放在低地址
  • 小端序:數(shù)值的低位存放在低地址翩瓜,高位存放在高地址受扳;
    例如:


    image.png

數(shù)值本身低位在右邊,由右向左奥溺,即:低位-》高位辞色;
在實(shí)際場(chǎng)景中,字節(jié)序有兩種:

  • 網(wǎng)絡(luò)字節(jié)序:字節(jié)在網(wǎng)絡(luò)中傳輸?shù)木幣彭樞蚋《ǎ趖cp/ip協(xié)議中相满,使用的是大端序;
  • 主機(jī)字節(jié)序: 數(shù)值在內(nèi)存中的存儲(chǔ)順序桦卒,不同cpu使用方式不同立美,有的是大端序,有的是小端序方灾,普遍的是小端序建蹄;
    各自優(yōu)勢(shì):
  • Big Endian:符號(hào)位的判定固定為第一個(gè)字節(jié),容易判斷正負(fù)裕偿。
  • Little Endian:長(zhǎng)度為1洞慎,2,4字節(jié)的數(shù)嘿棘,排列方式都是一樣的劲腿,數(shù)據(jù)類型轉(zhuǎn)換非常方便。小字節(jié)類型轉(zhuǎn)換成大字節(jié)鸟妙,因?yàn)轫樞蛞恢陆谷耍恍枰诤竺婕?即可;
    所以當(dāng)從網(wǎng)絡(luò)中接收字節(jié)數(shù)據(jù)后需要轉(zhuǎn)換成小端序后重父,再對(duì)數(shù)據(jù)進(jìn)行處理花椭。

Go中在encoding/binary 包中的全局變量BigEndian用于操作大端序數(shù)據(jù),LittleEndian用于操作小端序數(shù)據(jù)房午,這兩個(gè)變量所對(duì)應(yīng)的數(shù)據(jù)類型都實(shí)行了ByteOrder接口:

type ByteOrder interface {
  // 用于讀取
    Uint16([]byte) uint16
    Uint32([]byte) uint32
    Uint64([]byte) uint64
// 用于寫入
    PutUint16([]byte, uint16)
    PutUint32([]byte, uint32)
    PutUint64([]byte, uint64)
    String() string
}

看個(gè)具體例子:

//判斷系統(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")
    }
}

func testBigEndian() {
    //00000000 00000000 00000000 00001111
    var testInt uint32 = 15
    fmt.Printf("%d use big endian: \n", testInt)
    var testBytes []byte = make([]byte, 4)
    binary.BigEndian.PutUint32(testBytes, testInt)
    fmt.Println("int32 to bytes:", testBytes)

    convInt := binary.BigEndian.Uint32(testBytes)
    fmt.Printf("bytes to int32: %d\n\n", convInt)
}

func testLittleEndian() {
    //00000000 00000000 00000000 00001111
    var testInt uint32 = 15
    fmt.Printf("%d use little endian: \n", testInt)
    var testBytes []byte = make([]byte, 4)
    binary.LittleEndian.PutUint32(testBytes, testInt)
    fmt.Println("int32 to bytes:", testBytes)

    convInt := binary.LittleEndian.Uint32(testBytes)
    fmt.Printf("bytes to int32: %d\n\n", convInt)
}

輸出:
system edian is big endian
15 use big endian: 
int32 to bytes: [0 0 0 15]
bytes to int32: 15

15 use little endian: 
int32 to bytes: [15 0 0 0]
bytes to int32: 15

四 go實(shí)現(xiàn)簡(jiǎn)單bitmap

位運(yùn)算的一個(gè)使用場(chǎng)景矿辽,構(gòu)造一個(gè)位圖

package main

import "fmt"

type bitMap struct {
    data []byte
    size int
}

func NewBitMap(size int) *bitMap {
    bm := &bitMap{}
    if size > 0 {
        bm.size = size
    }
    return bm
}

// 獲取在字節(jié)數(shù)組中下標(biāo),num除以8 就得到num在數(shù)組中的位置
// num / 8 == num >> 3
func (bm *bitMap) GetIndex(num uint) uint {
    return num >> 3
}

// 獲取在一個(gè)字節(jié)中的位的位置郭厌,byte[index]中的第幾位
// num % 8得到在一個(gè)字節(jié)中的位置
func (bm *bitMap) GetPosition(num uint) uint {
    return num & (8 - 1)
}

// 標(biāo)記指定數(shù)字(num)在bitmap中的值袋倔,標(biāo)記其已經(jīng)出現(xiàn)過
// 將1左移position后,那個(gè)位置自然就是1沪曙,然后和以前的數(shù)據(jù)做或運(yùn)算,這樣萎羔,那個(gè)位置就替換成1了
func (bm *bitMap) Add(num uint) {
    index := bm.GetIndex(num)
    bm.data[index] |= 1 << bm.GetPosition(num)
}

// 判斷num是否在位圖中
// 將1左移position位置后液走,那個(gè)位置自然就是1,然后和以前的數(shù)據(jù)做與運(yùn)算,判斷是否為1
// 如果結(jié)果為1缘眶,則以前那個(gè)位置就是1嘱根,否則以前的那個(gè)位置的數(shù)是0
func (bm *bitMap) Contains(num uint) bool {
    index := bm.GetIndex(num)
    return bm.data[index]&1<<bm.GetPosition(num) == 1
}

// 打印byte類型變量
// 把byte轉(zhuǎn)換為一個(gè)長(zhǎng)度為8的數(shù)組,數(shù)組每個(gè)值代表bit
func (bm *bitMap) ShowByte(b byte) {
    array := make([]byte, 8)

    for i := 0; i < 8; i++ {
        array[i] = b & 1
        b = b >> 1
    }

    for _, b1 := range array {
        fmt.Println(b1)
    }
}

引用:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巷懈,一起剝皮案震驚了整個(gè)濱河市该抒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顶燕,老刑警劉巖凑保,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涌攻,居然都是意外死亡欧引,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門恳谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芝此,“玉大人,你說我怎么就攤上這事因痛』槠唬” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵鸵膏,是天一觀的道長(zhǎng)膊升。 經(jīng)常有香客問我,道長(zhǎng)较性,這世上最難降的妖魔是什么用僧? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮赞咙,結(jié)果婚禮上责循,老公的妹妹穿的比我還像新娘。我一直安慰自己攀操,他們只是感情好院仿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著速和,像睡著了一般歹垫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颠放,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天排惨,我揣著相機(jī)與錄音,去河邊找鬼碰凶。 笑死暮芭,一個(gè)胖子當(dāng)著我的面吹牛鹿驼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辕宏,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼畜晰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了瑞筐?” 一聲冷哼從身側(cè)響起凄鼻,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎聚假,沒想到半個(gè)月后块蚌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魔策,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年匈子,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闯袒。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虎敦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出政敢,到底是詐尸還是另有隱情其徙,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布喷户,位于F島的核電站唾那,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏褪尝。R本人自食惡果不足惜闹获,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望河哑。 院中可真熱鬧避诽,春花似錦、人聲如沸璃谨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)佳吞。三九已至拱雏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間底扳,已是汗流浹背铸抑。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衷模,地道東北人鹊汛。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓菇爪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親柒昏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345