欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

簡(jiǎn)單聊聊Go語言中空結(jié)構(gòu)體和空字符串的特殊之處

 更新時(shí)間:2024年03月25日 16:29:30   作者:胡譯胡說  
在日常的編程過程中,大家應(yīng)該經(jīng)常能遇到各種”空“吧,比如空指針、空結(jié)構(gòu)體、空字符串等,本文就以?Go?語言為例,一起來看看空結(jié)構(gòu)體和空字符串在?Go?語言中的特殊之處吧

在日常的編程過程中,大家應(yīng)該經(jīng)常能遇到各種”空“吧,比如空指針、空結(jié)構(gòu)體、空字符串……代碼中的這些”空“往往是特例,都有特殊的性質(zhì)。

本文就以 Go 語言為例,一起來看看空結(jié)構(gòu)體空字符串在 Go 語言中的特殊之處。

首先是空結(jié)構(gòu)體。

Go 語言中的空結(jié)構(gòu)體

我們先來運(yùn)行這樣一段代碼。

// https://go.dev/play/p/L2YxOr8k6Qq
package main

type U struct{}
type V struct{}

func main() {
    var i = 10

    var u = U{}
    var v = V{}

    println("i address =", &i)
    println("u address =", &u)
    println("v address =", &v)
}

// 運(yùn)行結(jié)果
// i address = 0xc000046730
// u address = 0xc000046730
// v address = 0xc000046730

iu、v 這 3 個(gè)變量的內(nèi)存地址竟然完全一樣!

uv 的內(nèi)存地址相同就已經(jīng)有點(diǎn)出乎意料了,畢竟它們的類型不同,一個(gè)是 struct U 的實(shí)例(值),一個(gè)是 struct V 的實(shí)例。但更出乎意料的是,這個(gè)內(nèi)存地址竟然還是變量 i 的地址(如下圖)。

這是因?yàn)?struct Ustruct V 都是空結(jié)構(gòu)體這種特殊的結(jié)構(gòu)體,而空結(jié)構(gòu)體的實(shí)例,即 struct{}{},不占用任何存儲(chǔ)空間,圖中自然也就找不到存儲(chǔ)著 struct{}{} 的空間。

不占用存儲(chǔ)空間且內(nèi)存地址相同,這就是空結(jié)構(gòu)體這種“空”的特點(diǎn)。

更有意思的是,既然 u (或 v)的地址就是變量 i 的地址,那通過 u 應(yīng)該也能讀出存儲(chǔ)在 0xc000046730 這個(gè)位置的整數(shù) 10吧。 讓我們來試一試。

println(*(*int)(unsafe.Pointer(&u)))

果然可以!

下面我們?cè)賮砜纯戳硪环N“空”——空字符串。

Go 語言中的空字符串

下面這段代碼會(huì)輸出什么呢?交替出現(xiàn)的 Sora 和空行嗎?

// https://go.dev/play/p/c1ZfChdH0rT
package main

import "fmt"

func main() {
    title := ""
    go func() {
        for {
            fmt.Println(title)
        }
    }()

    for {
        go func() {
            title = ""
        }()

        go func() {
            title = "Sora"
        }()
    }
}

竟然 painc 了,意不意外?

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x462cca]

goroutine 18 [running]:
fmt.(*buffer).writeString(...)
    /usr/local/go-faketime/src/fmt/print.go:108
fmt.(*fmt).padString(0x425000000041f01c?, {0x0, 0x4})
    /usr/local/go-faketime/src/fmt/format.go:110 +0x24a
...
fmt.Println(...)
    /usr/local/go-faketime/src/fmt/print.go:314
main.main.func1()
    /tmp/sandbox3517788398/prog.go:9 +0x5a
created by main.main in goroutine 1
    /tmp/sandbox3517788398/prog.go:7 +0x66

下面就來分析一下背后的原因(從本節(jié)的標(biāo)題也能猜出吧,八成和title = ""這里的空字符串有關(guān))。

首先,由倒數(shù)第 3 行的 /tmp/sandbox3517788398/prog.go:9 +0x5a 可見,導(dǎo)致 panic 的代碼是第 9 行的 fmt.Println(title)。

而 “破案”的線索就在報(bào)錯(cuò)信息的這一行(第 7 行):

fmt.(*fmt).padString(0x425000000041f01c?, {0x0, 0x4})

接下來我們先找出 fmt.padString() 函數(shù)的定義。

// https://github.com/golang/go/blob/master/src/fmt/format.go#L110

// padString appends s to f.buf, ...
func (f *fmt) padString(s string) {

對(duì)照著定義,可以猜出 {0x0, 0x4} 對(duì)應(yīng)的正是參數(shù) s string。

那再結(jié)合字符串類型 string 在 Go 語言中的定義,

// https://github.com/golang/go/blob/master/src/internal/unsafeheader/unsafeheader.go#L34
type String struct {
    Data unsafe.Pointer
    Len  int
}

不難推測(cè)出,這里相當(dāng)于我們將 String{Data: 0x0, Len: 0x4} 這樣一個(gè)表示字符串的結(jié)構(gòu)體傳遞給了 fmt.padString()。而這是一個(gè)長(zhǎng)度為 4 的空字符串

這里沒有寫錯(cuò),就是長(zhǎng)度為 4 的空字符串。

既然長(zhǎng)度為 4,那別管空不空,fmt.Println() 就要通過存在于 Data 中的指針(地址)取出這“4個(gè)字符”——計(jì)算機(jī)就是這么“誠(chéng)實(shí)”。但 Data == 0x0,是空指針,當(dāng)然就空指針 panic 了,即報(bào)錯(cuò)信息中的“invalid memory address or nil pointer dereference”。

“案子”是破了,可“長(zhǎng)度為 4 的空字符串”又是怎么產(chǎn)生的呢?

罪魁禍?zhǔn)拙驮谶@一對(duì)兒協(xié)程上,

    for {
        go func() {
            title = ""
        }()

        go func() {
            title = "Sora"
        }()
    }

看似通過 = 一下子就能把字符串賦給變量 title,但實(shí)際上不得不依次對(duì) DataLen 賦值,比如,

go routine1: title.Data = <空字符串""的地址> = 0x0
go routine1: title.Len  = <空字符串""的長(zhǎng)度> = 0

go routine2: title.Data = <字符串"Sora"的地址>
go routine2: title.Len  = <字符串"Sora"的長(zhǎng)度> = 4

而當(dāng)這一對(duì)兒協(xié)程并發(fā)執(zhí)行時(shí),以上 2 組“語句”的執(zhí)行順序是不確定的,完全有可能出現(xiàn)以下二者交替執(zhí)行情況:

go routine2: title.Data = <字符串"Sora"的地址>
    go routine1: title.Data = <空字符串""的地址> = 0x0
    go routine1: title.Len  = <空字符串""的長(zhǎng)度> = 0
go routine2: title.Len  = <字符串"Sora"的長(zhǎng)度> = 4

于是導(dǎo)致了{Data: 0x0, Len: 0x4},即長(zhǎng)度為 4 的空字符串。

painc 的“案子”終于破了。

本文通過兩個(gè)小例子簡(jiǎn)單介紹了 Go 語言中的“空”,諸位也可以測(cè)試測(cè)試其他語言中的“空”有什么特性。

到此這篇關(guān)于簡(jiǎn)單聊聊Go語言中空結(jié)構(gòu)體和空字符串的特殊之處的文章就介紹到這了,更多相關(guān)Go空結(jié)構(gòu)體和空字符串內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go語言實(shí)現(xiàn)字符串base64編碼的方法

    go語言實(shí)現(xiàn)字符串base64編碼的方法

    這篇文章主要介紹了go語言實(shí)現(xiàn)字符串base64編碼的方法,實(shí)例分析了Go語言操作字符串的技巧及base64編碼的使用技巧,需要的朋友可以參考下
    2015-03-03
  • go通過benchmark對(duì)代碼進(jìn)行性能測(cè)試詳解

    go通過benchmark對(duì)代碼進(jìn)行性能測(cè)試詳解

    在開發(fā)中我們要想編寫高性能的代碼,或者優(yōu)化代碼的性能時(shí),你首先得知道當(dāng)前代碼的性能,在go中可以使用testing包的benchmark來做基準(zhǔn)測(cè)試 ,文中有詳細(xì)的代碼示例,感興趣的小伙伴可以參考一下
    2023-04-04
  • 詳解如何在Go中使用Zap管理日志

    詳解如何在Go中使用Zap管理日志

    Zap提供了兩種類型的日志記錄器—Sugared?Logger和Logger,可以更好的管理日志,這篇文章主要為大家介紹了使用Zap管理日志的具體方法,需要的可以了解一下
    2023-07-07
  • Go 類型轉(zhuǎn)換工具包strconv包的用法

    Go 類型轉(zhuǎn)換工具包strconv包的用法

    Go 語言的?strconv?包提供了用于基本數(shù)據(jù)類型之間轉(zhuǎn)換的函數(shù),本文主要介紹了Go 類型轉(zhuǎn)換工具包strconv包的用法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • go?語言爬蟲庫(kù)goquery的具體使用

    go?語言爬蟲庫(kù)goquery的具體使用

    GoQuery是專為Go語言設(shè)計(jì)的一個(gè)強(qiáng)大的HTML解析和查詢庫(kù),本文主要介紹了go語言爬蟲庫(kù)goquery的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法

    go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法

    這篇文章主要介紹了go語言goto語句跳轉(zhuǎn)到指定的標(biāo)簽實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 探索Golang?Redis實(shí)現(xiàn)發(fā)布訂閱功能實(shí)例

    探索Golang?Redis實(shí)現(xiàn)發(fā)布訂閱功能實(shí)例

    這篇文章主要介紹了Golang?Redis發(fā)布訂閱功能實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 深入了解Golang網(wǎng)絡(luò)編程N(yùn)et包的使用

    深入了解Golang網(wǎng)絡(luò)編程N(yùn)et包的使用

    net包主要是增加?context?控制,封裝了一些不同的連接類型以及DNS?查找等等,同時(shí)在有需要的地方引入?goroutine?提高處理效率。本文主要和大家分享下在Go中網(wǎng)絡(luò)編程的實(shí)現(xiàn),需要的可以參考一下
    2022-07-07
  • Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解

    Golang使用ttl機(jī)制保存內(nèi)存數(shù)據(jù)方法詳解

    ttl(time-to-live) 數(shù)據(jù)存活時(shí)間,我們這里指數(shù)據(jù)在內(nèi)存中保存一段時(shí)間,超過期限則不能被讀取到,與Redis的ttl機(jī)制類似。本文僅實(shí)現(xiàn)ttl部分,不考慮序列化和反序列化
    2023-03-03
  • Go語言導(dǎo)出內(nèi)容到Excel的方法

    Go語言導(dǎo)出內(nèi)容到Excel的方法

    這篇文章主要介紹了Go語言導(dǎo)出內(nèi)容到Excel的方法,涉及Go語言操作excel的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02

最新評(píng)論