Go 憑什麼不支援三元運算子?

煎魚發表於2021-11-01

大家好,我是煎魚。

這是一個很多其他語言工程師轉 Go 語言的時間節點,這就難免不論一番比較。其中一個經典的運算上的就是 “三元運算子”:

圖片

為什麼 Go 語言不支援三元運算子,Go 不支援三元運算子就是設計的不好,是歷史在開倒車嗎?

今天就由煎魚來和大家一起摸索為什麼。

三元運算子是什麼

三元運算子,在典型的數學意義上,或者從解析器的角度來看,是一個需要三個引數的運算子。而我們日常中,最常見的是二元運算子:

x + y
x / y
x * y

還有一元運算子:

-a
~b
!c

以及今天的男主角 “三元運算子”。在 C/C++ 等多種語言中,我們可以根據條件宣告和初始化變數的習慣來選擇性使用三元條件運算子:

int index = val > 0 ? val : -val

Go 使用三元運算子

想在 Go 語言裡也使用三元運算子時,發現居然沒有...想要實現與上面相同的程式碼段的方式似乎只能:

var index int

if val > 0 {
    index = val
} else {
    index = -val
}

看上去十分的冗餘,不夠簡潔。

為什麼 Go 沒有三元運算子

為什麼 Go 沒有 ?: 操作符,沒有的話,官方推薦的方式是怎麼樣的。

通過 Go FAQ 我們可以得知:

圖片

Go 官方就是推薦我們使用前面提到的方式來替代,並且明確瞭如下態度:

  • Go 中沒有 ?: 的原因是語言的設計者看到這個操作經常被用來建立難以理解的複雜表示式。
  • 在替代方案上,if-else 形式雖然較長,但無疑是更清晰的。一門語言只需要一個條件控制流結構。

整體來講,Go 語言的設計者是為了考慮可讀性拒絕了實現三元運算子,"less is more." 也是標榜臺詞了。

社群爭議

Go 語言的一些點與眾不同,基本是大家皆知的。無論是 if err != nil,又或是本次的三元運算子,要大家用 if-else 替代:

if expr {
    n = trueVal
} else {
    n = falseVal
}

反對和同意

反對

因此有社群小夥伴給出了反對,基本分為如下幾類:

  1. 認為 if-else 也有以類似情況能被濫用,設計者的理由不夠充分,認為是 “藉口”。
  2. 認為三元運算子的 “醜陋” 問題,是開發者的編碼問題,而不是語言問題。三元在各種語言中很常見,它們是正常的,Go 語言也應該要有。
  3. 認為用 if-else 替代三元運算子也很麻煩,讓開發者多讀了 3-4 行和額外的縮排級別。

同意

認可這個決策的也有不少,為此給出了大量的真實工程案例。

一般來講,我們用三元運算子是希望這麼用:

cond ? true_value : false_value

你可能見過這麼用:

cond ? value_a + value_b : value_c * value_d

還見過這樣:

(((cond_a ? val_one) : cond_b) ? val_two) : val_three

cond_a ? (val_one : (cond_b ? (val_two : val_three)))

還能巢狀三元運算子:

int a = cond_a ? val_one :
    cond_b ? val_two :
    cond_c ? val_three : val_four;

也能出現可讀性更差的:

void rgb_to_lightness_(
  const double re, const double gr, const double bl, double &li)
{
  li=((re < gr) ? ((gr < bl) ? bl : gr) : ((re < bl) ? bl : re) +
                            (gr < re)
                          ? ((bl < gr) ? bl : gr)
                          : ((bl < re) ? bl : re)) / 2.0;
}

說白了就是真實的程式碼工程中,大家見到過大量三元運算子濫用的場景,紛紛給出了大量的難理解的例子,讓大家困擾不堪。

總結

在這篇文章中,首先針對 “三元運算子” 做了基本的介紹。緊接著根據 Go 語言不支援三元的態度進行了說明,且面向社群的爭議我們分為了正反方面的基本詮釋。

實際上一個簡單的 ?: 既整潔又實用,但是沒有很好又高效的辦法方法可以防止醜陋的巢狀,也就是排除可讀性的問題。

在真實的業務工程中,常常能看到一個三元運算子,一開始只是很簡單。後面巢狀越加越深,邏輯越寫越複雜,從而帶來了許多維護上的問題

給大家丟擲如下問題:

  • 你認為 Go 語言是否要有三元運算子呢?
  • 如果要有,複雜巢狀的三元運算子又如何考慮呢?

歡迎大家在評論區留言和交流 :)

若有任何疑問歡迎評論區反饋和交流,最好的關係是互相成就,各位的點贊就是煎魚創作的最大動力,感謝支援。

文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。

相關文章