最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

GO語言中ni,零值與空結(jié)構(gòu)體的使用

 更新時間:2024年10月16日 10:16:29   作者:飛空之羽  
Go語言為Java開發(fā)者帶來了一些新概念,如零值、nil和空結(jié)構(gòu)體,理解這些概念有助于Go語言的學(xué)習(xí)和應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

go語言的初學(xué)者,特別是java開發(fā)者新學(xué)習(xí)go語言,對于一些和java類似但是又有差異的概念很容易混淆,比如說go中的零值,nil 和 空結(jié)構(gòu)體。本文就來詳細(xì)探討一下go中這些特殊概念的含義和實際場景中的應(yīng)用:

零值

零值(The Zero Value)可以看作為當(dāng)你聲明了一個變量,但沒有顯式的初始化的時候,系統(tǒng)為變量賦予的一個默認(rèn)初始值。官方對零值的定義如下:

When storage is allocated for a variable, either through a declaration or a call of new, or when a new value is created, either through a composite literal or a call of make, and no explicit initialization is provided, the variable or value is given a default value. Each element of such a variable or value is set to the zero value for its type: false for booleans, 0 for numeric types, “” for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.

據(jù)此我們可總結(jié)出:

  • 值類型 布爾類型為 false, 數(shù)值類型為 0,字符串為”“,數(shù)組和結(jié)構(gòu)體(struct)會遞歸初始化其元素或字段,即其初始值取決于元素或字段。這里所謂的值類型其實就相當(dāng)于java中的 primary 類型,只是需要注意的是string在java中是對象類型,而go中string則是值類型。

  • 引用類型 均為 nil,包括指針 pointer,函數(shù) function,接口 interface,切片 slice,管道 channel,映射 map。

tip: 其實go里面沒有真正的引用類型,可以粗略的理解為值類型的變量直接存儲值,引用類型的變量存儲的是一個地址,這個地址用于存儲最終的值

值類型

因為有零值的存在,使得我們在使用變量時,大部分情況下可以不必進(jìn)行初始化而直接使用,這樣能夠保持代碼的簡潔性,也能夠盡量避免出現(xiàn)Java開發(fā)中常見的**NullPointerException,**以下是一些例子:

package main

import "sync"

type Value struct {
    mu sync.Mutex   //無需初始化,聲明就能用
    val int
}

func (v *Value)Incr(){
    defer v.mu.Unlock()
    v.mu.Lock()
    v.val++
}

func main() {
    var i Value
    i.Incr()
}

sync.Mutex本質(zhì)上是一個結(jié)構(gòu)體:

// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
	state int32
	sema  uint32
}

那么如果是引用類型,零值為nil,是不是就不能直接用了呢?這個實際上也要分情況,按照類型我們一個個來看:

切片(Slices)

切片的零值是一個nil slice,除了不能按照序號索引查詢以外,其它的操作都能做:

func testNilSlice() {
	var nilSlice []string
    fmt.Println(nilSlice == nil) // true
    fmt.Println(nilSlice[0]) //index out of range
	emptySlice = append(nilSlice, "dd") // append操作會自動擴(kuò)容
	fmt.Println(nilSlice[0]) //輸出dd
}

nil slice與not nil slice的區(qū)別:

type Person {
  Friends []string
}

var f1 []string //nil切片
json1, _ := json.Marshal(Person{Friends: f1})
fmt.Printf("%s\n", json1) //output:{"Friends": null}

f2 := make([]string, 0) //non-nil空切片 ,等價于 f2 := []string{}
json2, _ := json.Marshal(Person{Friends: f2})
fmt.Printf("%s\n", json2) //output: {"Friends": []}

推薦在日常使用時,沒有特殊需求都使用var nilSlice []string 這樣的形式聲明空切片:https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices

Map

對于nil的map,我們可以簡單把它看成是一個只讀的map,不能進(jìn)行寫操作,否則就會panic:

func testNilMap() {
	var m map[string]string
	fmt.Println(m["key"]) //輸出""
    m["key"]="value" //panic: assignment to entry in nil map
}

那么nil map有啥用呢,可以看看以下的例子:

func NewGet(url string, headers map[string]string) (*http.Request, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	for k, v := range headers {
		req.Header.Set(k, v)
	}
	return req, nil
}

//調(diào)用該方法時如果沒有header,可以傳入一個空的map,例如:
NewGet("http://google.com", map[string]string{})
//也可以直接傳入nil
NewGet("http://google.com", nil)

Channel

nil channel會阻塞對該channel的所有讀、寫。所以,可以將某個channel設(shè)置為nil,進(jìn)行強(qiáng)制阻塞,對于select分支來說,就是強(qiáng)制禁用此分支

func addIntegers(c chan int) {
    sum := 0
    t := time.NewTimer(time.Second)
    for {
        select {
            case input := <-c:
                sum = sum + input
            case <-t.C:
                c = nil
                fmt.Println(sum)  // 輸出10
        }
    }
}

func main() {
	c := make(chan int, 1)
	go addIntegers(c)
	for i := 0; i <= 10; i++ {
		c <- i
		time.Sleep(time.Duration(200) * time.Millisecond)
	}
}

指針(Pointers)

指針如果為nil,則對指針進(jìn)行解引用的話,會引發(fā)我們在java中非常熟悉的空指針錯誤

type Person struct {
	Name string
	Sex  string
	Age  int
}

var p *Person
fmt.Println(p.Name)  // panic: runtime error: invalid memory address or nil pointer dereference

神奇的nil

nil 是 Golang 中預(yù)先聲明的標(biāo)識符,其主要用來表示引用類型的零值(指針,接口,函數(shù),映射,切片和通道),表示它們未初始化的值。

// [src/builtin/builtin.go](https://golang.org/src/builtin/builtin.go#L98)
//
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

nil在go語言里面不是一個關(guān)鍵字或者保留字,所以你可以用nil作為變量名(作死):

var nil = errors.New("my god")

nil沒有默認(rèn)的類型,所以不能給一個未聲明類型的變量賦值,也不能和自己比較:

a := nil
// cannot declare variable as untyped nil: a
fmt.Println(nil == nil)
// invalid operation: nil == nil (operator == not defined on nil)
fmt.Printf("%T", nil)
// use of untyped nil

比較nil時一定要注意nil實際上是有類型的,不同類型的nil是不相等的,比如下面的例子:

var p *int
var i interface{}

fmt.Println(p)      // <nil>
fmt.Println(i)      // <nil>

fmt.Println(p == i) // false

再看一個在實際編碼里面很容易犯的錯誤:

type BusinessError struct {
	error
	errorCode int64
}

func doBusiness() *BusinessError {
	return nil
}

func wrapDoBusiness() error {
	err := doBusiness()
	return err
}

func testError() {
	err := wrapDoBusiness() //這里面拿到的本質(zhì)上是一個<T:*BusinessError,V:nil>的nil
	fmt.Println(err == nil)
}

建議:如果任何地方有判斷interface是否為 nil 值的邏輯,一定不要寫任何有關(guān)于將interface賦值為具體實現(xiàn)類型(可能為nil)的代碼,如果是 nil 值就直接賦給interface,而不要過具體類型的轉(zhuǎn)換

type BusinessError struct {
	error
	errorCode int64
}

func doBusiness() *BusinessError {
	return nil
}

func wrapDoBusiness() error {
	err := doBusiness() 
	if err == nil {
		return nil  //如果返回值為nil,直接返回nil,不要做類型轉(zhuǎn)換
	} else {
		return err
	}
}

func testError() {
	err := wrapDoBusiness()
	fmt.Println(err == nil)
}

空結(jié)構(gòu)體

golang 正常的 struct 就是普通的一個內(nèi)存塊,必定是占用一小塊內(nèi)存的,并且結(jié)構(gòu)體的大小是要經(jīng)過邊界,長度的對齊的,但是“空結(jié)構(gòu)體”是不占內(nèi)存的,size 為 0;

var q struct{}
fmt.Println(unsafe.Sizeof(q)) // 0

空結(jié)構(gòu)體 struct{ } 為什么會存在的核心理由就是為了節(jié)省內(nèi)存。當(dāng)你需要一個結(jié)構(gòu)體,但是卻絲毫不關(guān)系里面的內(nèi)容,那么就可以考慮空結(jié)構(gòu)體。以下是幾個經(jīng)典的用法:

map & struct{}

map 和 struct {} 一般的結(jié)合姿勢是這樣的:

// 創(chuàng)建 map
m := make(map[int]struct{})
// 賦值
m[1] = struct{}{}
// 判斷 key 鍵存不存在
_, ok := m[1]

一般 map 和 struct {} 的結(jié)合使用場景是:只關(guān)心 key,不關(guān)注值。比如查詢 key 是否存在就可以用這個數(shù)據(jù)結(jié)構(gòu),通過 ok 的值來判斷這個鍵是否存在,map 的查詢復(fù)雜度是 O(1) 的,查詢很快。這種方式在部分場景下可以起到類似Java中Set的作用

chan & struct{}

channel 和 struct{} 結(jié)合是一個最經(jīng)典的場景,struct{} 通常作為一個信號來傳輸,并不關(guān)注其中內(nèi)容。chan 本質(zhì)的數(shù)據(jù)結(jié)構(gòu)是一個管理結(jié)構(gòu)加上一個 ringbuffer ,如果 struct{} 作為元素的話,ringbuffer 就是 0 分配的。

chan 和 struct{} 結(jié)合基本只有一種用法,就是信號傳遞,空結(jié)構(gòu)體本身攜帶不了值,所以也只有這一種用法啦,一般來說,配合 no buffer 的 channel 使用。

waitc := make(chan struct{})

// ...
goroutine 1:
    // 發(fā)送信號: 投遞元素
    waitc <- struct{}
    // 發(fā)送信號: 關(guān)閉
    close(waitc)

goroutine 2:
    select {
    // 收到信號,做出對應(yīng)的動作
    case <-waitc:
    }

到此這篇關(guān)于GO語言中ni,零值與空結(jié)構(gòu)體的文章就介紹到這了,更多相關(guān)GO ni 零值 空結(jié)構(gòu)體內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • go嵌套匿名結(jié)構(gòu)體的初始化詳解

    go嵌套匿名結(jié)構(gòu)體的初始化詳解

    這篇文章主要介紹了go嵌套匿名結(jié)構(gòu)體的初始化詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang自動追蹤GitHub上熱門AI項目

    Golang自動追蹤GitHub上熱門AI項目

    這篇文章主要為大家介紹了Golang自動追蹤GitHub上熱門AI項目,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 對Golang中的runtime.Caller使用說明

    對Golang中的runtime.Caller使用說明

    這篇文章主要介紹了對Golang中的runtime.Caller使用說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go grpc高級用法

    go grpc高級用法

    RPC是遠(yuǎn)程過程調(diào)用,可以像調(diào)用本地服務(wù)一樣取調(diào)用遠(yuǎn)程服務(wù),本文主要介紹了go grpc高級用法,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • go語言反射的基礎(chǔ)教程示例

    go語言反射的基礎(chǔ)教程示例

    這篇文章主要為大家介紹了go語言反射的基礎(chǔ)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Golang通道阻塞情況與通道無阻塞實現(xiàn)小結(jié)

    Golang通道阻塞情況與通道無阻塞實現(xiàn)小結(jié)

    本文主要介紹了Golang通道阻塞情況與通道無阻塞實現(xiàn)小結(jié),詳細(xì)解析了通道的類型、操作方法以及垃圾回收機(jī)制,從基礎(chǔ)概念到高級應(yīng)用,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • Go?中?time.After?可能導(dǎo)致的內(nèi)存泄露問題解析

    Go?中?time.After?可能導(dǎo)致的內(nèi)存泄露問題解析

    這篇文章主要介紹了Go?中?time.After?可能導(dǎo)致的內(nèi)存泄露,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Go語言中rune方法使用詳解

    Go語言中rune方法使用詳解

    本文主要介紹了Go語言中rune方法使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Go語言學(xué)習(xí)之文件操作方法詳解

    Go語言學(xué)習(xí)之文件操作方法詳解

    這篇文章主要為大家詳細(xì)介紹了Go語言中一些常見的文件操作,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-04-04
  • goroutine?泄漏和避免泄漏實戰(zhàn)示例

    goroutine?泄漏和避免泄漏實戰(zhàn)示例

    這篇文章主要為大家介紹了goroutine?泄漏和避免泄漏實戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評論

青神县| 常熟市| 耒阳市| 潞城市| 永登县| 北票市| 辽源市| 依兰县| 海阳市| 澜沧| 汉沽区| 莱阳市| 栾川县| 龙游县| 库尔勒市| 阿城市| 和田市| 漯河市| 松江区| 色达县| 仙游县| 营山县| 屏东县| 渑池县| 万州区| 辛集市| 鄂托克旗| 新邵县| 乌苏市| 石楼县| 齐齐哈尔市| 积石山| 安国市| 调兵山市| 上饶县| 修文县| 贵定县| 江华| 扎鲁特旗| 龙州县| 墨竹工卡县|