<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Golang為何舍棄三元運算符

馬哥Linux運維 ? 來源:cnblogs ? 2024-04-03 15:13 ? 次閱讀

三元運算符廣泛存在于其他語言中,比如:

python

val = trueValue if expr else falseValue

javascript:

const val = expr ? trueValue : falseValue

c、c++

const char *val = expr ? "trueValue" : "falseValue";

然而,被廣泛支持的三目運算符在golang中卻是不存在的!如果我們寫出類似下面的代碼:

val := expr ? "trueValue" : "falseValue"

那么編譯器就該抱怨了:invalid character U+003F '?'。意思是golang中不存在?這個運算符,編譯器不認識而且非字母數字下劃線也不能用做變量名,自然也就當作是非法字符了。

然而這是為什么呢,其實官方給出了解釋,這里簡單引用一下:

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中不存在?:運算符的原因是因為語言設計者已經預見到三元運算符經常被用來構建一些極其復雜的表達式。雖然使用if進行替代會讓代碼顯得更長,但這毫無疑問可讀性更強。一個語言只需要有一種條件判斷結構就足夠了。

毫無疑問,這是在golang“大道至簡”的指導思想下的產物。

這段話其實沒問題,因為某些三元運算符的使用場景確實會降低代碼的可讀性:

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';

乍一看確實很復雜,至少第二個表達式不花個20秒細看可能沒法理清控制流程(想象一下當縮進錯位或是完全沒有縮進的時候)。

如果把它們直接轉化成if語句是這樣的:

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'
}
}
}

看起來并沒有多少的改善,特別是例2,三層嵌套,不管是誰review到這段代碼難免不會抱怨你幾句。

然而事實上這些代碼是可以簡化的,考慮到三元運算符總是會給變量一個值,因此最后的else其實可以看作是變量的默認值,于是代碼可以這么寫:

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'
}
}
}

其次,對于例2,顯然可以使用else if來清除嵌套結構:

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'
}

現在再來看,顯然使用if語句的版本的可讀性更高,邏輯也更清晰(通過去除嵌套)。

然而事實也不盡然。除了用三元運算符表達流程控制之外,事實上更常見更廣泛的一個應用是如下這樣的表達式:

const val = expr ? trueValue : falseValue
const func = (age) => age > 18 ? '成年人' : '未成年人'

類似上述通過一個簡短的條件表達式來確定變量的值,在開發中的出現頻率是相當高的。這時三元運算符的意圖更清晰,可讀性也較if語句更高,特別是配合匿名函數(lambda表達式)使用可以極大簡化我們的代碼。

對此python的解決之道是之支持上述的簡化版三元表達式,同時表達式不支持嵌套,達到了揚長避短的目的。不過代價是編譯器的相關實現會復雜化。

而對于golang來說一個簡單的能只通過單遍掃描即可完成ast構建的編譯器是其保持急速的構建速度的秘訣之一,為了這樣簡單的功能增加編譯器實現的復雜度是不可接受的。同時由于golang“大道至簡”的哲學,能用現有語法結構解決的問題,自然不會再添加新的語法。

不過還是有辦法的,雖然不推薦

func If(cond bool, a, b interface{}) {
if cond {
return a
}
return b
}
age := 20
val := If(age > 18, "成年人", "未成年人").(string)

不推薦這么做是有幾個原因:

使用接口導致性能下降

需要強制的類型斷言

不管三元表達式還是if語句,對于不會到達的分支是不會計算的,也就是惰性計算;而給函數傳遞參數時每一個表達式都會被計算

最后總結一下:

三元運算符的優點:

對于簡短的表達式使用三元運算符表意更清晰,特別是在習慣了線性閱讀三元運算符表達式之后

不需要中間狀態(例如第一個例子中的let變量可以替換為const,代碼更健壯),心智負擔更低

沒有中間狀態也就意味著更少或完全沒有副作用,代碼更易跟蹤和維護

但三元運算符也有明顯的缺點:

對于復雜邏輯代碼可讀性較差(例如第一個例子中的status,需要在trueValue的位置進行進一步的條件判斷時)

容易被濫用,很多人將其用于替代if語句或是簡化復雜的if嵌套,這會導致上一條中所描述的結果

條件分支只能為表達式,不支持多條語句

所以這是一個見仁見智的問題,總之只能入鄉隨俗了。

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編譯器
    +關注

    關注

    1

    文章

    1579

    瀏覽量

    48713
  • 運算符
    +關注

    關注

    0

    文章

    163

    瀏覽量

    10959

原文標題:為什么golang中不存在三元運算符

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Verilog 縮減運算符

    小弟剛學FPGA ,在看Veriolg ,遇到縮減運算符,對于縮減與 縮減或能理解,那個非本身就是單目運算,縮減非是怎么回事呢?
    發表于 10-07 10:13

    煉獄傳奇-移位和位拼運算符之戰

    運算符,就會使程序編寫起來變得簡單了。代碼的意思就是,每次把最低位放到最高位,讓前位放到后面,這樣邏輯“1”就實現了移位,形成了循環。
    發表于 04-30 09:43

    C語言運算符的優先級和結合性

    ;、a=c=d;等。 3) 像 +、-、*、/ 這樣的運算符,它的兩邊都有數據,例如 3+4、a*3 等,有兩個操作數,我們稱這樣的運算符為雙目運算符。后面還會講解單目運算符
    發表于 07-06 06:46

    【FPGA】VHDL 語言的運算符有哪些?計算的優先級是怎樣的?

    注意的是乘方(**)運算的右邊必須為整數。VHDL 的算術運算符如表 2-8 所示。4.移位運算符移位運算符為二
    發表于 09-12 09:51

    【夢翼師兄今日分享】 常見的關系運算符(移位運算符)

    立即學習>>夢翼師兄FPGA培訓(視頻加板卡),手把手帶你入門FPGA寫在前面的話移位運算符是雙目運算符,將運算符左邊的操作數左移或右移指定的位數,用0來補充空閑位。如果右邊操作數的值
    發表于 12-17 10:45

    【夢翼師兄今日分享】 常見的關系運算符(縮減運算符

    立即學習>>夢翼師兄FPGA培訓(視頻加板卡),手把手帶你入門FPGA寫在前面的話縮減運算符是單目運算符,也有與或非運算。其與或非運算規則類似于位
    發表于 12-17 10:48

    【夢翼師兄今日分享】 常見的關系運算符(位拼運算符

    立即學習>>夢翼師兄FPGA培訓(純視頻),手把手帶你入門FPGA寫在前面的話位拼運算符是將多個小的表達式合并形成一個大的表達式,用符號{}來實現多個表達式的連接運算,各個表達式之間用
    發表于 12-19 09:38

    C語言運算符優先級(超詳細)

    C語言運算符優先級(超詳細) 當想找哪個運算符優先級高時,很多時候總是想找的就沒有,真讓人氣憤!現在,終于有個我個人覺得非常全的,分享給大家,歡迎拍磚!C語言運算符優先級[table]優先級
    發表于 04-27 16:47

    Java基礎之Java運算符

    在Java中,表達式是由運算符和操作數組成的。比如,我們可以把下面的都稱為表達式:5num1num1+num2sum=num1+num2Java的運算符包括:算術運算符、賦值運算符、關
    發表于 05-18 15:39

    如何去使用運算符?

    運算的定義是什么?運算符是由什么組成的?如何去使用運算符?
    發表于 07-15 13:13

    C語言中運算符? :怎么使用?

    C語言中運算符? :怎么使用?
    發表于 11-02 09:23

    算術運算符的相關資料分享

    一:算術運算符算術運算符非常地簡單,就是小學數學里面的一些加減乘除操作。不過呢,還是有一些語法細節需要注意的。1.加法運算符 + 1 在第3行利用加法運算符 + 進行了加法
    發表于 11-30 06:09

    運算符的相關資料推薦

    運算符1、算數操作運算符+、-、*、/、%加法:A+B, AB最好是同類型乘除:乘法在很多CPU中并不支持,乘除法能不用就不用,可能會使執行變差求模/求余數:n%m=res[0~(m-1)]求模
    發表于 12-24 06:13

    2.7 python運算符

    優先級的所有運算符:[table][td]運算符描述**指數 (最高優先級)~,+,-按位翻轉, 一加號和減號 (最后兩個的方法名為 +@ 和 -@)*,/,%,//乘,除,取模和取整除+,-加法減法
    發表于 02-21 16:43

    條件(三元運算符

    RTL建模中廣泛使用的運算符是條件運算符,也稱為三元運算符,該運算符用于在兩個表達式之間進行選擇——表5-2列出了用于表示條件
    的頭像 發表于 02-09 15:42 ?1069次閱讀
    條件(<b class='flag-5'>三元</b>)<b class='flag-5'>運算符</b>
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>