三元運(yùn)算符廣泛存在于其他語(yǔ)言中,比如:
val = trueValue if expr else falseValue |
javascript:
const val = expr ? trueValue : falseValue |
c、c++:
const char *val = expr ? "trueValue" : "falseValue"; |
然而,被廣泛支持的三目運(yùn)算符在golang中卻是不存在的!如果我們寫出類似下面的代碼:
val := expr ? "trueValue" : "falseValue" |
那么編譯器就該抱怨了:invalid character U+003F '?'。意思是golang中不存在?這個(gè)運(yùn)算符,編譯器不認(rèn)識(shí)而且非字母數(shù)字下劃線也不能用做變量名,自然也就當(dāng)作是非法字符了。
然而這是為什么呢,其實(shí)官方給出了解釋,這里簡(jiǎn)單引用一下:
The reason ?: is absent from Go is that the language's designers had seen the operation used too often to create impenetrably complex expressions. The if-else form, although longer, is unquestionably clearer. A language needs only one conditional control flow construct.
golang中不存在?:運(yùn)算符的原因是因?yàn)檎Z(yǔ)言設(shè)計(jì)者已經(jīng)預(yù)見到三元運(yùn)算符經(jīng)常被用來(lái)構(gòu)建一些極其復(fù)雜的表達(dá)式。雖然使用if進(jìn)行替代會(huì)讓代碼顯得更長(zhǎng),但這毫無(wú)疑問(wèn)可讀性更強(qiáng)。一個(gè)語(yǔ)言只需要有一種條件判斷結(jié)構(gòu)就足夠了。
毫無(wú)疑問(wèn),這是在golang“大道至簡(jiǎn)”的指導(dǎo)思想下的產(chǎn)物。
這段話其實(shí)沒(méi)問(wèn)題,因?yàn)槟承┤\(yùn)算符的使用場(chǎng)景確實(shí)會(huì)降低代碼的可讀性:
const status = (type===1?(agagin===1?'再售':'已售'):'未售') | |
const word = (res.distance === 0) ? 'a' | |
: (res.distance === 1 && res.difference > 3) ? 'b' | |
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' | |
: 'd'; |
乍一看確實(shí)很復(fù)雜,至少第二個(gè)表達(dá)式不花個(gè)20秒細(xì)看可能沒(méi)法理清控制流程(想象一下當(dāng)縮進(jìn)錯(cuò)位或是完全沒(méi)有縮進(jìn)的時(shí)候)。
如果把它們直接轉(zhuǎn)化成if語(yǔ)句是這樣的:
let status = '' | |
if (type === 1) { | |
if (again === 1) { | |
status = '再售' | |
} else { | |
status = '已售' | |
} | |
} else { | |
status = '未售' | |
} | |
let word = '' | |
if (res.distance === 0) { | |
word = 'a' | |
} else { | |
if (res.distance === 1 && res.difference > 3) { | |
word = 'b' | |
} else { | |
if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) { | |
word = 'c' | |
} else { | |
word = 'd' | |
} | |
} | |
} |
看起來(lái)并沒(méi)有多少的改善,特別是例2,三層嵌套,不管是誰(shuí)review到這段代碼難免不會(huì)抱怨你幾句。
然而事實(shí)上這些代碼是可以簡(jiǎn)化的,考慮到三元運(yùn)算符總是會(huì)給變量一個(gè)值,因此最后的else其實(shí)可以看作是變量的默認(rèn)值,于是代碼可以這么寫:
let status = '未售' | |
if (type === 1) { | |
if (again === 1) { | |
status = '再售' | |
} else { | |
status = '已售' | |
} | |
} | |
let word = 'd' | |
if (res.distance === 0) { | |
word = 'a' | |
} else { | |
if (res.distance === 1 && res.difference > 3) { | |
word = 'b' | |
} else { | |
if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) { | |
word = 'c' | |
} | |
} | |
} |
其次,對(duì)于例2,顯然可以使用else if來(lái)清除嵌套結(jié)構(gòu):
let word = 'd' | |
if (res.distance === 0) { | |
word = 'a' | |
} else if (res.distance === 1 && res.difference > 3) { | |
word = 'b' | |
} else if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) { | |
word = 'c' | |
} |
現(xiàn)在再來(lái)看,顯然使用if語(yǔ)句的版本的可讀性更高,邏輯也更清晰(通過(guò)去除嵌套)。
然而事實(shí)也不盡然。除了用三元運(yùn)算符表達(dá)流程控制之外,事實(shí)上更常見更廣泛的一個(gè)應(yīng)用是如下這樣的表達(dá)式:
const val = expr ? trueValue : falseValue | |
const func = (age) => age > 18 ? '成年人' : '未成年人' |
類似上述通過(guò)一個(gè)簡(jiǎn)短的條件表達(dá)式來(lái)確定變量的值,在開發(fā)中的出現(xiàn)頻率是相當(dāng)高的。這時(shí)三元運(yùn)算符的意圖更清晰,可讀性也較if語(yǔ)句更高,特別是配合匿名函數(shù)(lambda表達(dá)式)使用可以極大簡(jiǎn)化我們的代碼。
對(duì)此python的解決之道是之支持上述的簡(jiǎn)化版三元表達(dá)式,同時(shí)表達(dá)式不支持嵌套,達(dá)到了揚(yáng)長(zhǎng)避短的目的。不過(guò)代價(jià)是編譯器的相關(guān)實(shí)現(xiàn)會(huì)復(fù)雜化。
而對(duì)于golang來(lái)說(shuō)一個(gè)簡(jiǎn)單的能只通過(guò)單遍掃描即可完成ast構(gòu)建的編譯器是其保持急速的構(gòu)建速度的秘訣之一,為了這樣簡(jiǎn)單的功能增加編譯器實(shí)現(xiàn)的復(fù)雜度是不可接受的。同時(shí)由于golang“大道至簡(jiǎn)”的哲學(xué),能用現(xiàn)有語(yǔ)法結(jié)構(gòu)解決的問(wèn)題,自然不會(huì)再添加新的語(yǔ)法。
不過(guò)還是有辦法的,雖然不推薦:
func If(cond bool, a, b interface{}) { | |
if cond { | |
return a | |
} | |
return b | |
} | |
age := 20 | |
val := If(age > 18, "成年人", "未成年人").(string) |
不推薦這么做是有幾個(gè)原因:
使用接口導(dǎo)致性能下降
需要強(qiáng)制的類型斷言
不管三元表達(dá)式還是if語(yǔ)句,對(duì)于不會(huì)到達(dá)的分支是不會(huì)計(jì)算的,也就是惰性計(jì)算;而給函數(shù)傳遞參數(shù)時(shí)每一個(gè)表達(dá)式都會(huì)被計(jì)算
最后總結(jié)一下:
三元運(yùn)算符的優(yōu)點(diǎn):
對(duì)于簡(jiǎn)短的表達(dá)式使用三元運(yùn)算符表意更清晰,特別是在習(xí)慣了線性閱讀三元運(yùn)算符表達(dá)式之后
不需要中間狀態(tài)(例如第一個(gè)例子中的let變量可以替換為const,代碼更健壯),心智負(fù)擔(dān)更低
沒(méi)有中間狀態(tài)也就意味著更少或完全沒(méi)有副作用,代碼更易跟蹤和維護(hù)
但三元運(yùn)算符也有明顯的缺點(diǎn):
對(duì)于復(fù)雜邏輯代碼可讀性較差(例如第一個(gè)例子中的status,需要在trueValue的位置進(jìn)行進(jìn)一步的條件判斷時(shí))
容易被濫用,很多人將其用于替代if語(yǔ)句或是簡(jiǎn)化復(fù)雜的if嵌套,這會(huì)導(dǎo)致上一條中所描述的結(jié)果
條件分支只能為表達(dá)式,不支持多條語(yǔ)句
所以這是一個(gè)見仁見智的問(wèn)題,總之只能入鄉(xiāng)隨俗了。
審核編輯:黃飛
-
編譯器
+關(guān)注
關(guān)注
1文章
1654瀏覽量
49871 -
運(yùn)算符
+關(guān)注
關(guān)注
0文章
172瀏覽量
11339
原文標(biāo)題:為什么golang中不存在三元運(yùn)算符
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
C語(yǔ)言運(yùn)算符的使用方法

條件運(yùn)算符是什么_條件運(yùn)算符有哪些

單目運(yùn)算符是什么_單目運(yùn)算符有哪些

C運(yùn)算符的優(yōu)先級(jí)和結(jié)合性詳細(xì)解決
淺析MySQL中的各類運(yùn)算符

干貨:三大實(shí)例講解三種C++運(yùn)算符重載

python運(yùn)算符是什么
SystemVerilog-運(yùn)算符/表達(dá)式規(guī)則
如何靈活使用三元運(yùn)算符
什么是運(yùn)算符重載
條件(三元)運(yùn)算符

Go語(yǔ)言運(yùn)算符主要包括哪些呢?

評(píng)論