您現在的位置是:首頁 > 遊戲

一道比較運算子相關的面試題把我虐的體無完膚

由 新世界雜貨鋪 發表于 遊戲2022-04-25
簡介一、interface{}不為nil,且動態型別均為可比較型別時:上述輸出結果為true false false,這符合動態型別和動態value均一致時才相等的原則

布林值怎麼比較

來自公眾號:新世界雜貨鋪

雜(貨鋪)談

今天這篇文章相對來說比較基礎,大家花幾分鐘時間看看,有所收穫自然是最好,沒有收穫也就消磨幾分鐘時間罷了,你不虧,筆者也不虧~

前幾期還是有一定難度的HTTP系列文章,今天卻是畫風突變講起了基礎,這當然是因為基礎重要呀。正所謂萬丈高樓平地起,我們夯實基礎,樓才能建的高,畢竟精美的小矮樓總是很容易被高樓遮擋。嗨,扯遠了,總之筆者今天寫這篇文章絕對不是下面這個原因:

累呀!真的累!工作嘛?當然不是!前幾期分析HTTP系列文章確實耗費了太多精力,週末連續熬夜就算是鐵打的人也扛不住,所以本週只有養精蓄銳這一個目的。

雜(貨鋪)言

Go中的比較運算子,你真的瞭解嗎?假如面試官問你下面輸出什麼,你的答案是什麼?

一道比較運算子相關的面試題把我虐的體無完膚

今天,筆者總結了一份比較運算子的相關文件,助力讀者夯實基礎(上述答案請參考後文)。

基本定理

在Go中,比較運算子也是遵循定理的, 兩條基本定理如下:

定理一

:相等運算子

==

!=

適用於具有可比性的運算元,排序運算子

<

<=

>

>=

適用於可排序的運算元。

定理二

:在任何比較中,至少滿足一個運算元能賦值給另一個運算元型別的變數。

常見型別的比較

常見型別的比較大家都懂,在這裡筆者就不詳細介紹了,僅列舉一下原則加深大家的印象:

布林值是可比較的,但不可排序,即僅適用於

==

!=

運算子。

整數和浮點數是可比較的且可排序,適用於所有比較運算子。

字串的值是可比較的,且按位元組排序,即比較時按位元組比較大小(不理解字串和位元組切片關係的,請參考深入理解go中字串這篇文章)。

以上即為常見型別的比較原則,下面我們結合例子逐步理解各種型別之間的比較。

不可比較的型別

在Go中,

切片

map

,和

func

是不可比較的,他們僅可以和預宣告表示符

nil

進行比較。能和nil進行比較的還有

指標

管道

interface{}

複數之間的比較

複數可比較但不可排序,實部和虛部均相等兩個複數才相等

。複數僅適用

==

!=

這兩個比較運算子:

一道比較運算子相關的面試題把我虐的體無完膚

上述輸出結果為

false

,證明覆數之間可比較。

一道比較運算子相關的面試題把我虐的體無完膚

此時程式無法執行,在vscode中的錯誤提醒為

cannot compare c1 >= c2 (operator >= not defined for complex128)compiler

。由此確認複數不可排序。

結構體之間的比較

如果結構體的所有欄位都是可比較的,則他們所有非匿名欄位的值相等,結構體的值才相等

。驗證如下:

一道比較運算子相關的面試題把我虐的體無完膚

上述輸出分別為

true

false

。由此驗證非匿名欄位的值相等,結構體的值才相等。

fmt。Println(st1 <= st2)

此行程式碼在vscode中的錯誤提醒為

cannot compare st1 <= st2 (operator <= not defined for canC)compiler

。由此可知,即使結構體滿足比較條件也無法適用於

<

<=

>

>=

運算子。

:後文中提到不可排序均代表著無法適用於

<

<=

>

>=

運算子,在後文中不再對不可排序給出例子。

下面看看包含匿名欄位的結構體比較時有什麼不同:

一道比較運算子相關的面試題把我虐的體無完膚

上述輸出為

true

,符合非匿名欄位的值相等時結構體的值相等這一原則。注意,

如果匿名欄位是不可比較的型別時,上述程式碼會編譯報錯

最後我們看看包含不可比較型別的結構體:

一道比較運算子相關的面試題把我虐的體無完膚

上述程式碼在vscode中的錯誤提醒為

cannot compare (canNotC literal) == (canNotC literal) (operator == not defined for canNotC)compiler

,由此可知,結構體如果要可比較,則其內部的所有欄位必須全為可比較型別。

指標之間的比較

指標是可比較的,但不可排序

。如果兩個指標指向同一個變數,或者兩個指標值均為nil,則這兩個指標相等。相信讀者對於這一點應該是沒有異議的,但是有一個情況卻是十分需要注意的。

zero-size variables

:如果結構體沒有任何欄位或者陣列沒有任何元素,則其大小為0,即

unsafe.Sizeof

的計算結果為0。兩個不同的

zero-size variables

在記憶體中可能具有相同的地址。

指向不同zero-size variables的兩個指標可能相等也可能不相等

一道比較運算子相關的面試題把我虐的體無完膚

筆者多次執行,

parr1 == parr2

始終輸出為

false

,目前尚未發現輸出為

true

的情況,在https://github。com/golang/go/issues/23440也有人遇到同筆者相同的情況,所以筆者就不再對此問題做更近一步的分析。

Channel之間的比較

在寫這篇文章前,筆者從來都沒有想過Channel之間是可以比較的。事實上,管道是可比較型別,golang原文如下:

Channel values are comparable。 Two channel values are equal if they were created by the same callto make orifboth have value nil

這裡需要注意的是,只有相同呼叫的管道才是相等的:

一道比較運算子相關的面試題把我虐的體無完膚

上述中,

cint1

cint2

初始值均為nil,所以輸出

true

。雙向通道

cint4

賦值給單向通道

cint1

時,滿足相同的

make

呼叫這一條件,所以輸出也為

true

Interface{}之間比較

Interface{}是可比較的,但是不可排序。兩個Interface{}變數的動態型別和動態value均一致它們才相等,兩個變數均為nil也是相等的

。針對這一原則筆者對其分以下幾種情況討論。

一、interface{}不為nil,且動態型別均為可比較型別時:

一道比較運算子相關的面試題把我虐的體無完膚

上述輸出結果為

true false false

,這符合

動態型別和動態value均一致時才相等

的原則。

二、

如果比較雙方動態型別一致且為不可比較型別時會panic

這種情況可正常編譯,但是會造成執行時崩潰,所以一定要注意!!!

fmt。Println(i5 == i6)

fmt。Println(i7 == i6)

上述比較

i5

i6

時能夠正常輸出,但是

i6

i7

比較時出現如下錯誤:

一道比較運算子相關的面試題把我虐的體無完膚

所以,筆者在這裡再次強調,如果專案中有不小心直接使用了

interface{}

進行比較的,請一定要注意。

三、動態value為nil的interface{}不一定等於nil:

一道比較運算子相關的面試題把我虐的體無完膚

由上述程式碼知,如果不是直接返回

nil

interface{}

nil

進行比較時是不相等的。相信很多人在平時的開發中都有可能會忽略這個問題。下面我們對它為什麼不相等進行簡單的分析。

在Go中,

interface{}

的實現為兩個元素,型別

t

和值

v

。v是一個具體的值,如int、struct、或指標等。

如果,我們在介面中儲存int值3,則介面中的值為(t=int,v=3)。

值v也稱為介面的動態值,因為在程式執行期間,給定的介面變數可能包含不同的值v(以及相應的型別t)。

只有當v和t都未設定時,介面值才是nil(t=nil,未設定v)。

如果,我們在介面中儲存一個型別為

int的nil指標, 那麼不管指標的值是什麼,內部型別都會是

int:(t=*int,v=nil)。因此,即使內部的指標v為nil,這樣的介面值也是非nil的。

本部分內容翻譯整理自https://golang。org/doc/faq#nil_error

非介面型別X實現了介面T,則X的變數x能和T的變數t進行比較

原則:

非介面型別X實現了介面T,則X的變數x能和T的變數t進行比較。只有當t的動態變數型別為X且t的動態value和x相等時,t才等於x

推論:又因為go中任意型別都預設實現了

interface{}

,則意味著

interface{}

變數能和任意的非

interface{}

型別的可比較型別進行比較。

驗證原則:

一道比較運算子相關的面試題把我虐的體無完膚

上面的輸出分別為

false

true

,符合原則。

驗證推論:

var it1 interface{} = “111”

fmt。Println(it1 == 1)

上面能夠正常比較,說明推論正確,且輸出為

false

,符合原則。

注意

:下面情況會panic

一道比較運算子相關的面試題把我虐的體無完膚

上述程式碼發生panic,符和

Interface{}

之間比較的原則。

陣列之間的比較

兩個陣列的元素型別相同且是可比較型別,並且陣列的長度相同,則這兩個陣列可比較。當兩個可比較的陣列對應元素均相等時,則這兩個陣列相等。即使兩個陣列可比較,但依舊不可排序

型別相同但元素不可比較時:

一道比較運算子相關的面試題把我虐的體無完膚

上述程式碼在vscode中的錯誤為

cannot compare array1 == array2 (operator == not defined for [3][]int)compiler

,所以如果陣列元素為不可比較型別,則陣列也不可比較。

陣列元素可比較但陣列長度不一致時:

一道比較運算子相關的面試題把我虐的體無完膚

上述程式碼在vscode中的錯誤為

cannot compare array3 == array4 (mismatched types [3]int and [2]int)compiler

,所以如果陣列長度不一致時,則兩個陣列不可比較。

滿足陣列長度相等且元素型別可比較時:

一道比較運算子相關的面試題把我虐的體無完膚

上述輸出分別為

true

false

,符合可比較陣列一一判斷對應元素是否相等這一原則。所以,我們平時在開發中可以利用該原則快速比較陣列是否相等。

最後,衷心希望本文能夠對各位讀者有一定的幫助。

寫本文時, 筆者所用go版本為: go1。14。2

文章中所用完整例子:https://github。com/Isites/go-coder/blob/master/comparison-operators/main。go

參考:

https://golang。org/ref/spec#Comparison_operators

推薦文章

  • 國產退役大軍艦迎江而上,引發全民圍觀,未來還有更大驚喜!

    由於目前中國海軍的新艦建造服役速度要遠遠快於老艦的退役速度,因此,未來還有更大驚喜,中國海軍現役導彈驅逐艦的數量在未來10年內追平美國海軍也並不是完全不可能的事情...

  • 一張嘴就有一股臭味,怎麼刷牙都沒用?1分鐘瞭解口臭“根源”

    要保持口氣清新,很多人會第一時間想到刷牙,這固然是最直接最根本的處理辦法,但出門在外,不可能時刻準備牙膏、牙刷、漱口水這類口腔清潔用品,無奈火鍋、烤肉太過吸引,還有很多人無大蒜、洋蔥、辣椒、榴蓮不歡,如果有一款能隨身攜帶口氣清新產品就太好了...

  • 簡單易學的印尼醬油膏炒麵,GET 新技能!

    用料乾麵條(泡麵餅更好)1人份胡蘿蔔1根捲心菜1/4顆洋蔥酥(熱狗裡用的就ok)3大勺印尼甜醬油膏KetjapManis2大勺糖、鹽各半小勺白胡椒1/4小勺雞蛋製作煎蛋,1個或者不新增做法1準備好喜愛的蔬菜,甜椒絲,土豆絲,洋蔥絲,白蘿蔔...