亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

go語(yǔ)言定義零值可用的類型學(xué)習(xí)教程

 更新時(shí)間:2023年06月26日 11:11:50   作者:九路  
這篇文章主要為大家介紹了go語(yǔ)言定義零值可用的類型教程學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

1. Go 類型的零值

作為 C 程序員出身的我,我總是喜歡用在使用 C 語(yǔ)言的”受過(guò)的苦“與 Go 語(yǔ)言中得到的”甜頭“做比較,從而來(lái)證明 Go 語(yǔ)言設(shè)計(jì)者在當(dāng)初設(shè)計(jì) Go 語(yǔ)言時(shí)是做了充分考量的。

在 C99 規(guī)范中,有一段是否對(duì)棧上局部變量進(jìn)行自動(dòng)清零初始化的描述:

如果未顯式初始化且具有自動(dòng)存儲(chǔ)持續(xù)時(shí)間的對(duì)象,則其值是不確定的。

規(guī)范的用語(yǔ)總是晦澀難懂的。這句話大致的意思就是:如果是在棧上分配的局部變量,且在聲明時(shí)未對(duì)其進(jìn)行顯式初始化,那么這個(gè)變量的值是不確定的。比如:

// varinit.c
#include <stdio.h>
static int cnt;
void f() {
    int n;
    printf("local n = %d\n", n);
    if (cnt > 5) {
        return;
    }
    cnt++;
    f();
}
int main() {
    f();
    return 0;
}

編譯上面的程序并執(zhí)行:

// 環(huán)境 centos linux gcc 版本 4.1.2
// 注意:在您的環(huán)境中執(zhí)行上述代碼,輸出的結(jié)果很大可能與這里有所不同
$ gcc varinit.c
$ ./a.out
local n = 0
local n = 10973
local n = 0
local n = 52
local n = 0
local n = 52
local n = 52

我們看到分配在棧上的未初始化變量的值是不確定的,雖然一些編譯器的較新版本也都提供一些命令行參數(shù)選項(xiàng)用于對(duì)棧上變量進(jìn)行零值初始化,比如 GCC 就提供如下命令行選項(xiàng):

-finit-local-zero
-finit-derived
-finit-integer=n
-finit-real=<zero|inf|-inf|nan|snan>
-finit-logical=<true|false>
-finit-character=n

但這并不能改變 C 語(yǔ)言原生不支持對(duì)未顯式初始化局部變量進(jìn)行零值初始化的事實(shí)。資深 C 程序員是深知這個(gè)陷阱帶來(lái)的問(wèn)題是有多嚴(yán)重的。因此同樣出身于 C 語(yǔ)言的 Go 設(shè)計(jì)者們?cè)?Go 中徹底對(duì)這個(gè)問(wèn)題進(jìn)行的修復(fù)和優(yōu)化。根據(jù)Go 語(yǔ)言規(guī)范

當(dāng)通過(guò)聲明或調(diào)用new為變量分配存儲(chǔ)空間,或者通過(guò)復(fù)合文字字面量或make調(diào)用創(chuàng)建新值,
并且還不提供顯式初始化的情況下,Go會(huì)為變量或值提供默認(rèn)值。

Go 語(yǔ)言的每種原生類型都有其默認(rèn)值,這個(gè)默認(rèn)值就是這個(gè)類型的零值。下面是 Go 規(guī)范定義的內(nèi)置原生類型的默認(rèn)值(零值)。

所有整型類型:0

浮點(diǎn)類型:0.0

布爾類型:false

字符串類型:""

指針、interface、slice、channel、map、function:nil

另外 Go 的零值初始是遞歸的,即諸如數(shù)組、結(jié)構(gòu)體等類型的零值初始化就是對(duì)其組成元素逐一進(jìn)行零值初始化。

2. 零值可用

我們現(xiàn)在知道了 Go 類型的零值,接下來(lái)我們來(lái)說(shuō)“可用”。

Go 從誕生以來(lái)就秉承著盡量保持“零值可用”的理念,我們來(lái)看兩個(gè)例子。

第一個(gè)例子是關(guān)于 slice 的:

var zeroSlice []int
zeroSlice = append(zeroSlice, 1)
fmt.Println(zeroSlice) // 輸出:[1]

我們聲明了一個(gè) []int 類型的 slice:zeroSlice,我們并沒(méi)有對(duì)其進(jìn)行顯式初始化,這樣 zeroSlice 這個(gè)變量被 Go 編譯器置為零值:nil。按傳統(tǒng)的思維,對(duì)于值為 nil 這樣的變量我們要給其賦上合理的值后才能使用。但是 Go 具備零值可用的特性,我們可以直接對(duì)其使用 append 操作,并且不會(huì)出現(xiàn)引用 nil 的錯(cuò)誤。

第二個(gè)例子是通過(guò) nil 指針調(diào)用方法的:

// callmethodthroughnilpointer.go
package main
import (
        "fmt"
        "net"
)
func main() {
        var p *net.TCPAddr
        fmt.Println(p) //輸出:<nil>
}

我們聲明了一個(gè) net.TCPAddr 的指針變量,我們并未對(duì)其顯式初始化,指針變量 p 會(huì)被 Go 編譯器賦值為 nil。我們?cè)跇?biāo)準(zhǔn)輸出上輸出該變量,fmt.Println 會(huì)調(diào)用 p.String()。我們來(lái)看看 TCPAddr 這個(gè)類型的 String 方法實(shí)現(xiàn):

// $GOROOT/src/net/tcpsock.go
func (a *TCPAddr) String() string {
        if a == nil {
                return "<nil>"
        }
        ip := ipEmptyString(a.IP)
        if a.Zone != "" {
                return JoinHostPort(ip+"%"+a.Zone, itoa(a.Port))
        }
        return JoinHostPort(ip, itoa(a.Port))
}

我們看到 Go 標(biāo)準(zhǔn)庫(kù)在定義 TCPAddr 類型以及其方法時(shí)充分考慮了“零值可用”的理念,使得通過(guò)值為 nil 的 TCPAddr 指針變量依然可以調(diào)用 String 方法。

在 Go 標(biāo)準(zhǔn)庫(kù)和運(yùn)行時(shí)代碼中還有很多踐行“零值可用”理念的好例子,最典型的莫過(guò)于 sync.Mutex 和 bytes.Buffer 了。

我們先來(lái)看看 sync.Mutex。在 C 語(yǔ)言中,如果我們要使用線程互斥鎖,我們需要這么做:

pthread_mutex_t mutex; // 不能直接使用
// 必須先進(jìn)行初始化
pthread_mutex_init (&mutex, NULL);
// 然后才能執(zhí)行l(wèi)ock或unlock
pthread_mutex_lock(&mutex); 
pthread_mutex_unlock(&mutex); 

但是在 Go 語(yǔ)言中,我們只需這么做:

var mu sync.Mutex
mu.Lock()
mu.Unlock()

Go 標(biāo)準(zhǔn)庫(kù)的設(shè)計(jì)者很“貼心”地將 sync.Mutex 結(jié)構(gòu)體的零值狀態(tài)設(shè)計(jì)為可用狀態(tài),這樣讓 Mutex 的調(diào)用者可以“省略”對(duì) Mutex 的初始化而直接使用 Mutex。

Go 標(biāo)準(zhǔn)庫(kù)中的 bytes.Buffer 亦是如此:

// bytesbufferwrite.go
package main
import (
        "bytes"
)
func main() {
        var b bytes.Buffer
        b.Write([]byte("Effective Go"))
        fmt.Println(b.String()) // 輸出:Effective Go
}

我們看到我們無(wú)需對(duì) bytes.Buffer 類型的變量 b 進(jìn)行任何顯式初始化即可直接通過(guò) b 調(diào)用其方法進(jìn)行寫入操作,這源于 bytes.Buffer 底層存儲(chǔ)數(shù)據(jù)的是同樣支持零值可用策略的 slice 類型:

// $GOROOT/src/bytes/buffer.go
// 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.
type Buffer struct {
        buf      []byte // contents are the bytes buf[off : len(buf)]
        off      int    // read at &buf[off], write at &buf[len(buf)]
        lastRead readOp // last read operation, so that Unread* can work correctly.
}

3. 小結(jié)

Go 語(yǔ)言零值可用的理念給內(nèi)置類型、標(biāo)準(zhǔn)庫(kù)的使用者帶來(lái)很多便利。不過(guò) Go 并非所有類型都是零值可用的,并且零值可用也是有一定限制的,比如:slice 的零值可用不能通過(guò)下標(biāo)形式操作數(shù)據(jù):

var s []int
s[0] = 12 // 報(bào)錯(cuò)!
s = append(s, 12) // OK

另外像 map 這樣的內(nèi)置類型也沒(méi)有提供零值可用的支持:

var m map[string]int
m["tonybai"] = 1 // 報(bào)錯(cuò)!
m1 := make(map[string]int
m1["tonybai"] = 1 // OK

另外零值可用的類型要注意盡量避免值拷貝:

var mu sync.Mutex
mu1 := mu // Error: 避免值拷貝
foo(mu) // Error: 避免值拷貝

我們可以通過(guò)指針?lè)绞絺鬟f類似 Mutex 這樣的類型。

對(duì)于我們 Go 開發(fā)者而言,保持與 Go 一致的理念,給自定義的類型一個(gè)合理的零值,并堅(jiān)持保持自定義類型是零值可用的,這樣我們的 Go 代碼會(huì)表現(xiàn)的更加符合 Go 慣用法。

以上就是go語(yǔ)言定義零值可用的類型的詳細(xì)內(nèi)容,更多關(guān)于go 零值可用類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程

    Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程

    這篇文章主要為大家介紹了Go語(yǔ)言自帶測(cè)試庫(kù)testing使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Golang標(biāo)準(zhǔn)庫(kù)之errors包應(yīng)用方式

    Golang標(biāo)準(zhǔn)庫(kù)之errors包應(yīng)用方式

    Go語(yǔ)言的errors包提供了基礎(chǔ)的錯(cuò)誤處理能力,允許通過(guò)errors.New創(chuàng)建自定義error對(duì)象,error在Go中是一個(gè)接口,通過(guò)實(shí)現(xiàn)Error方法來(lái)定義錯(cuò)誤文本,對(duì)錯(cuò)誤的比較通常基于對(duì)象地址,而非文本內(nèi)容,因此即使兩個(gè)錯(cuò)誤文本相同
    2024-10-10
  • GO語(yǔ)言字符串處理Strings包的函數(shù)使用示例講解

    GO語(yǔ)言字符串處理Strings包的函數(shù)使用示例講解

    這篇文章主要為大家介紹了GO語(yǔ)言字符串處理Strings包的函數(shù)使用示例講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • golang生成JSON以及解析JSON

    golang生成JSON以及解析JSON

    這篇文章主要介紹了golang生成JSON以及解析JSON,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • go 判斷兩個(gè) slice/struct/map 是否相等的實(shí)例

    go 判斷兩個(gè) slice/struct/map 是否相等的實(shí)例

    這篇文章主要介紹了go 判斷兩個(gè) slice/struct/map 是否相等的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 更換GORM默認(rèn)SQLite驅(qū)動(dòng)出現(xiàn)的問(wèn)題解決分析

    更換GORM默認(rèn)SQLite驅(qū)動(dòng)出現(xiàn)的問(wèn)題解決分析

    這篇文章主要為大家介紹了更換GORM默認(rèn)SQLite驅(qū)動(dòng)出現(xiàn)的問(wèn)題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • go語(yǔ)言中的協(xié)程詳解

    go語(yǔ)言中的協(xié)程詳解

    本文詳細(xì)講解了go語(yǔ)言中的協(xié)程,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Golang使用Token來(lái)驗(yàn)證

    Golang使用Token來(lái)驗(yàn)證

    token指的是一種用于驗(yàn)證用戶身份或授權(quán)訪問(wèn)的憑證,本文主要介紹了Golang使用Token來(lái)驗(yàn)證,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-08-08
  • Go JSON編碼與解碼的實(shí)現(xiàn)

    Go JSON編碼與解碼的實(shí)現(xiàn)

    這篇文章主要介紹了Go JSON編碼與解碼的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • go語(yǔ)言中sort包的實(shí)現(xiàn)方法與應(yīng)用詳解

    go語(yǔ)言中sort包的實(shí)現(xiàn)方法與應(yīng)用詳解

    golang中也實(shí)現(xiàn)了排序算法的包sort包,所以下面這篇文章主要給大家介紹了關(guān)于go語(yǔ)言中sort包的實(shí)現(xiàn)方法與應(yīng)用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11

最新評(píng)論