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

深入理解Go之==的使用

 更新時間:2025年11月14日 11:43:30   作者:donnyxia1128  
本文主要介紹了深入理解Go之==的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

概述

相信==判等操作,大家每天都在用。之前在論壇上看到不少人在問 golang ==比較的結(jié)果。看到很多人對 golang 中==的結(jié)果不太了解。確實,golang 中對==的處理有一些細(xì)節(jié)的地方需要特別注意。雖然平時可能不太會遇到,但是碰到了就是大坑。本文將對 golang 中==操作做一個系統(tǒng)的介紹。希望能對大家有所幫助。

類型

golang 中的數(shù)據(jù)類型可以分為以下 4 大類:

  1. 基本類型:整型(int/uint/int8/uint8/int16/uint16/int32/uint32/int64/uint64/byte/rune等)、浮點數(shù)(float32/float64)、復(fù)數(shù)類型(complex64/complex128)、字符串(string)。
  2. 復(fù)合類型(又叫聚合類型):數(shù)組和結(jié)構(gòu)體類型。
  3. 引用類型:切片(slice)、map、channel、指針。
  4. 接口類型:如error。

==操作最重要的一個前提是:兩個操作數(shù)類型必須相同!類型必須相同!類型必須相同!

如果類型不同,那么編譯時就會報錯。

注意:

  1. golang 的類型系統(tǒng)非常嚴(yán)格,沒有C/C++中的隱式類型轉(zhuǎn)換。雖然寫起來稍微有些麻煩,但是能避免今后非常多的麻煩?。。?/li>
  2. golang 中可以通過type定義新類型。新定義的類型與底層類型不同,不能直接比較。

為了更容易看出類型,示例代碼中的變量定義都顯式指定了類型。

看下面的代碼:

package main
 
import "fmt"
 
func main() {
    var a int8
    var b int16
    // 編譯錯誤:invalid operation a == b (mismatched types int8 and int16)
    fmt.Println(a == b)
}

沒有隱式類型轉(zhuǎn)換。

package main
 
import "fmt"
 
func main() {
    type int8 myint8
    var a int8
    var b myint8
    // 編譯錯誤:invalid operation a == b (mismatched types int8 and myint8)
    fmt.Println(a == b)
}

雖然myint8的底層類型是int8,但是他們是不同的類型。

下面依次通過這 4 種類型來說明==是如何做比較的。

基本類型

這是最簡單的一種類型。比較操作也很簡單,直接比較值是否相等。沒啥好說的,直接看例子。

var a uint32 = 10
var b uint32 = 20
var c uint32 = 10
fmt.Println(a == b) // false
fmt.Println(a == c) // true

有一點需要注意,浮點數(shù)的比較問題:

var a float64 = 0.1
var b float64 = 0.2
var c float64 = 0.3
fmt.Println(a + b == c) // false

因為計算機(jī)中,有些浮點數(shù)不能精確表示,浮點運算結(jié)果會有誤差。如果我們分別輸出a+bc的值,會發(fā)現(xiàn)它們確實是不同的:

fmt.Println(a + b)
fmt.Println(c)
 
// 0.30000000000000004
// 0.3

這個問題不是 golang 獨有的,只要浮點數(shù)遵循 IEEE 754 標(biāo)準(zhǔn)的編程語言都有這個問題。需要特別注意,盡量不要做浮點數(shù)比較,確實需要比較時,計算兩個浮點數(shù)的差的絕對值,如果小于一定的值就認(rèn)為它們相等,比如1e-9

復(fù)合類型

復(fù)合類型也叫做聚合類型。golang 中的復(fù)合類型只有兩種:數(shù)組和結(jié)構(gòu)體。它們是逐元素/字段比較的。

注意:數(shù)組的長度視為類型的一部分,長度不同的兩個數(shù)組是不同的類型,不能直接比較。

  • 對于數(shù)組來說,依次比較各個元素的值。根據(jù)元素類型的不同,再依據(jù)是基本類型、復(fù)合類型、引用類型或接口類型,按照特定類型的規(guī)則進(jìn)行比較。所有元素全都相等,數(shù)組才是相等的。
  • 對于結(jié)構(gòu)體來說,依次比較各個字段的值。根據(jù)字段類型的不同,再依據(jù)是 4 中類型中的哪一種,按照特定類型的規(guī)則進(jìn)行比較。所有字段全都相等,結(jié)構(gòu)體才是相等的。

例如:

a := [4]int{1, 2, 3, 4}
b := [4]int{1, 2, 3, 4}
c := [4]int{1, 3, 4, 5}
fmt.Println(a == b) // true
fmt.Println(a == c) // false
 
type A struct {
    a int
    b string
}
aa := A { a : 1, b : "test1" }
bb := A { a : 1, b : "test1" }
cc := A { a : 1, b : "test2" }
fmt.Println(aa == bb)
fmt.Println(aa == cc)

引用類型

引用類型是間接指向它所引用的數(shù)據(jù)的,保存的是數(shù)據(jù)的地址。引用類型的比較實際判斷的是兩個變量是不是指向同一份數(shù)據(jù),它不會去比較實際指向的數(shù)據(jù)。

例如:

type A struct {
    a int
    b string
}
 
aa := &A { a : 1, b : "test1" }
bb := &A { a : 1, b : "test1" }
cc := aa
fmt.Println(aa == bb)
fmt.Println(aa == cc)

因為aabb指向的兩個不同的結(jié)構(gòu)體,雖然它們指向的值是相等的(見上面復(fù)合類型的比較),但是它們不等。 aacc指向相同的結(jié)構(gòu)體,所以它們相等。

再看看channel的比較:

ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
ch3 := ch1
 
fmt.Println(ch1 == ch2)
fmt.Println(ch1 == ch3)

ch1ch2雖然類型相同,但是指向不同的channel,所以它們不等。 ch1ch3指向相同的channel,所以它們相等。

關(guān)于引用類型,有兩個比較特殊的規(guī)定:

  • 切片之間不允許比較。切片只能與nil值比較。
  • map之間不允許比較。map只能與nil值比較。

為什么要做這樣的規(guī)定?我們先來說切片。因為切片是引用類型,它可以間接的指向自己。例如:

a := []interface{}{ 1, 2.0 }
a[1] = a
fmt.Println(a)
 
// !!!
// runtime: goroutine stack exceeds 1000000000-byte limit
// fatal error: stack overflow

上面代碼將a賦值給a[1]導(dǎo)致遞歸引用,fmt.Println(a)語句直接爆棧。

  • 切片如果直接比較引用地址,是不合適的。首先,切片與數(shù)組是比較相近的類型,比較方式的差異會造成使用者的混淆。另外,長度和容量是切片類型的一部分,不同長度和容量的切片如何比較?
  • 切片如果像數(shù)組那樣比較里面的元素,又會出現(xiàn)上來提到的循環(huán)引用的問題。雖然可以在語言層面解決這個問題,但是 golang 團(tuán)隊認(rèn)為不值得為此耗費精力。

基于上面兩點原因,golang 直接規(guī)定切片類型不可比較。使用==比較切片直接編譯報錯。

例如:

var a []int
var b []int
 
// invalid operation: a == b (slice can only be compared to nil)
fmt.Println(a == b)

錯誤信息很明確。

因為map的值類型可能為不可比較類型(見下面,切片是不可比較類型),所以map類型也不可比較??。

接口類型

接口類型是 golang 中比較重要的一種類型。接口類型的值,我們稱為接口值。一個接口值是由兩個部分組成的,具體類型(即該接口存儲的值的類型)和該類型的一個值。引用《go 程序設(shè)計語言》的名稱,分別稱為動態(tài)類型動態(tài)值。接口值的比較涉及這兩部分的比較,只有當(dāng)動態(tài)類型完全相同且動態(tài)值相等(動態(tài)值使用==比較),兩個接口值才是相等的。

例如:

var a interface{} = 1
var b interface{} = 1
var c interface{} = 2
var d interface{} = 1.0
fmt.Println(a == b) // false
fmt.Println(a == c) // true
fmt.Println(a == d) // false

ab動態(tài)類型相同(都是int),動態(tài)值也相同(都是1,基本類型比較),故兩者相等。 ac動態(tài)類型相同,動態(tài)值不等(分別為12,基本類型比較),故兩者不等。 ad動態(tài)類型不同,aint,dfloat64,故兩者不等。

type A struct {
    a int
    b string
}
 
var aa interface{} = A { a: 1, b: "test" }
var bb interface{} = A { a: 1, b: "test" }
var cc interface{} = A { a: 2, b: "test" }
 
fmt.Println(aa == bb) // true
fmt.Println(aa == cc) // false
 
var dd interface{} = &A { a: 1, b: "test" }
var ee interface{} = &A { a: 1, b: "test" }
fmt.Println(dd == ee) // false
復(fù)制代碼

aabb動態(tài)類型相同(都是A),動態(tài)值也相同(結(jié)構(gòu)體A,見上面復(fù)合類型的比較規(guī)則),故兩者相等。 aacc動態(tài)類型相同,動態(tài)值不同,故兩者不等。 ddee動態(tài)類型相同(都是*A),動態(tài)值使用指針(引用)類型的比較,由于不是指向同一個地址,故不等。

注意:

如果接口的動態(tài)值不可比較,強(qiáng)行比較會panic?。?!

var a interface{} = []int{1, 2, 3, 4}
var b interface{} = []int{1, 2, 3, 4}
// panic: runtime error: comparing uncomparable type []int
fmt.Println(a == b)

ab的動態(tài)值是切片類型,而切片類型不可比較,所以a == bpanic。

接口值的比較不要求接口類型(注意不是動態(tài)類型)完全相同,只要一個接口可以轉(zhuǎn)化為另一個就可以比較。例如:

var f *os.File
var r io.Reader = f
var rc io.ReadCloser = f
fmt.Println(r == rc) // true
 
var w io.Writer = f
// invalid operation: r == w (mismatched types io.Reader and io.Writer)
fmt.Println(r == w)

r的類型為io.Reader接口,rc的類型為io.ReadCloser接口。查看源碼,io.ReadCloser的定義如下:

type ReadCloser interface {
	Reader
	Closer
}

io.ReadCloser可轉(zhuǎn)化為io.Reader,故兩者可比較。

io.Writer不可轉(zhuǎn)化為io.Reader,編譯報錯。

使用type定義的類型

使用type可以基于現(xiàn)有類型定義新的類型。新類型會根據(jù)它們的底層類型來比較。例如:

type myint int
var a myint = 10
var b myint = 20
var c myint = 10
fmt.Println(a == b) // false
fmt.Println(a == c) // true
 
type arr4 [4]int
var aa arr4 = [4]int{1, 2, 3, 4}
var bb arr4 = [4]int{1, 2, 3, 4}
var cc arr4 = [4]int{1, 2, 3, 5}
fmt.Println(aa == bb)
fmt.Println(aa == cc)

myint根據(jù)底層類型int來比較。 arr4根據(jù)底層類型[4]int來比較。

不可比較性

前面說過,golang 中的切片類型是不可比較的。所有含有切片的類型都是不可比較的。例如:

  • 數(shù)組元素是切片類型。
  • 結(jié)構(gòu)體有切片類型的字段。
  • 指針指向的是切片類型。

不可比較性會傳遞,如果一個結(jié)構(gòu)體由于含有切片字段不可比較,那么將它作為元素的數(shù)組不可比較,將它作為字段類型的結(jié)構(gòu)體不可比較。

談?wù)刴ap

由于mapkey是使用==來判等的,所以所有不可比較的類型都不能作為mapkey。例如:

// invalid map key type []int
m1 := make(map[[]int]int)
 
type A struct {
    a []int
    b string
}
// invalid map key type A
m2 := make(map[A]int)

由于切片類型不可比較,不能作為mapkey,編譯時m1 := make(map[[]int]int)報錯。 由于結(jié)構(gòu)體A含有切片字段,不可比較,不能作為mapkey,編譯報錯。

總結(jié)

到此這篇關(guān)于深入理解Go之==的使用的文章就介紹到這了,更多相關(guān)Go ==內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go快速開發(fā)一個RESTful API服務(wù)

    Go快速開發(fā)一個RESTful API服務(wù)

    這篇文章主要為大家介紹了Go快速開發(fā)一個RESTful API服務(wù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go實現(xiàn)socks5服務(wù)器的方法

    Go實現(xiàn)socks5服務(wù)器的方法

    SOCKS5 是一個代理協(xié)議,它在使用TCP/IP協(xié)議通訊的前端機(jī)器和服務(wù)器機(jī)器之間扮演一個中介角色,使得內(nèi)部網(wǎng)中的前端機(jī)器變得能夠訪問Internet網(wǎng)中的服務(wù)器,或者使通訊更加安全,這篇文章主要介紹了Go實現(xiàn)socks5服務(wù)器的方法,需要的朋友可以參考下
    2023-07-07
  • 基于Golang實現(xiàn)Excel表格的導(dǎo)入導(dǎo)出功能

    基于Golang實現(xiàn)Excel表格的導(dǎo)入導(dǎo)出功能

    最近項目開發(fā)中有涉及到Excel的導(dǎo)入與導(dǎo)出功能,特別是導(dǎo)出表格時需要特定的格式,所以本文給大家介紹了基于Golang實現(xiàn)Excel表格的導(dǎo)入導(dǎo)出功能,文中通過代碼示例和圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • 基于Go語言對浮點數(shù)進(jìn)行比較的方法

    基于Go語言對浮點數(shù)進(jìn)行比較的方法

    在 Go 語言(以及大多數(shù)遵循 IEEE 754 標(biāo)準(zhǔn)的編程語言)中,?差值容限(Epsilon) ? 是指在進(jìn)行浮點數(shù)比較時,允許兩個數(shù)值之間存在的最大微小誤差范圍,本文給大家介紹了基于Go語言對浮點數(shù)進(jìn)行比較的方法,需要的朋友可以參考下
    2026-05-05
  • Go?log模塊的使用技巧

    Go?log模塊的使用技巧

    Golog模塊是一個強(qiáng)大的日志記錄庫,提供了豐富的功能,如線程安全的日志記錄、靈活的日志格式配置、多種輸出目標(biāo)支持等,它還提供了錯誤處理和程序終止功能,以及自定義Logger的創(chuàng)建,本文給大家介紹Go?log模塊的使用,感興趣的朋友一起看看吧
    2025-11-11
  • golang 實現(xiàn)一個負(fù)載均衡案例(隨機(jī),輪訓(xùn))

    golang 實現(xiàn)一個負(fù)載均衡案例(隨機(jī),輪訓(xùn))

    這篇文章主要介紹了golang 實現(xiàn)一個負(fù)載均衡案例(隨機(jī)、輪訓(xùn)),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言中Seeker接口的用法詳解

    Go語言中Seeker接口的用法詳解

    Go語言標(biāo)準(zhǔn)庫中的io包提供了一系列接口,用于處理各種I/O操作,其中Seeker接口在處理大文件或需要隨機(jī)訪問的場景中非常有用,本文將結(jié)合具體案例,詳細(xì)介紹Go語言中io包的Seeker接口的用法,需要的朋友可以參考下
    2024-10-10
  • Golang實現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    Golang實現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map

    在項目實踐中,有時候我們需要將struct結(jié)構(gòu)體轉(zhuǎn)為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來介紹下常用的兩種轉(zhuǎn)換方式,希望對大家有所幫助
    2023-01-01
  • go?tar包歸檔文件處理操作全面指南

    go?tar包歸檔文件處理操作全面指南

    這篇文章主要為大家介紹了使用go?tar包歸檔文件處理操作全面指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 深入解析golang編程中函數(shù)的用法

    深入解析golang編程中函數(shù)的用法

    這篇文章主要介紹了golang編程中函數(shù)的用法,是Go語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-10-10

最新評論

当涂县| 牡丹江市| 磐安县| 靖边县| 读书| 迁安市| 邹平县| 崇信县| 琼海市| 昌吉市| 武宁县| 华阴市| 冕宁县| 五河县| 沧州市| 澳门| 晋江市| 普兰店市| 定西市| 龙海市| 环江| 黔西| 陵水| 万州区| 沂南县| 蓬溪县| 汕头市| 梨树县| 通榆县| 壶关县| 平安县| 阜平县| 斗六市| 北海市| 资阳市| 临潭县| 民县| 安泽县| 贵州省| 纳雍县| 贵德县|