這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
三元運算式的介紹在這裡:
- http://en.wikipedia.org/wiki/%3F:
- http://en.wikipedia.org/wiki/IIf
Go語言明確不支援三元運算式,這裡是相關的討論:
https://groups.google.com/d/msg/golang-nuts/dbyqx_LGUxM/tLFFSXSfOdQJ
官方FAQ的說明在這裡:
http://golang.org/doc/faq#Does_Go_have_a_ternary_form
官方FAQ推薦的做法是用 if 代替:
if expr { n = trueVal} else { n = falseVal}
不過用 if 的問題是變數 n 有範圍問題.
我們需要在 if 之前先定義變數 n,這樣才可以在 if 語句之後使用變數 n。
var n intif expr { n = trueVal} else { n = falseVal}println(n)
本來一個簡單的 n := expr? trueVal: falseVal 就能夠表達的問題,變的複雜了很多。
這和Go所追求的簡單思路是有衝突的。
類似的有 max/min 等函數。因為這類函數使用頻度比較高,在很多pkg的內部都定義了私人的實現。
func max(a, b int) int { if a < b { return b } return a}
熟悉Go語言的使用者應該可以發現,這個 max 只支援 int 類型。
對於支援泛型的C++語言來說,max 一般被實現為一個模板函數:
template <class T>const T& max (const T& a, const T& b) { return (a<b)?b:a; // or: return comp(a,b)?b:a; for version (2)}
在C++版本中,不僅用到的泛型T,還依賴 a<b 的運算子多載特性。
在C語言中,雖然沒有泛型和運算子多載,但是三元運算式也具備全部的特性(因為運算式天生就是支援泛型的)。
而這些都是Go語言中缺少的特性。
不過在Go語言中可以類比一個更普通的函數(If 的首字母大寫,是函數名,不是 if 關鍵字):
func If(condition bool, trueVal, falseVal interface{}) interface{} { if condition { return trueVal } return falseVal}a, b := 2, 3max := If(a > b, a, b).(int)println(max)
有幾個關鍵點:
- Go不支援運算子多載,因此需要先將
a<b 在函數外轉換為 bool 條件
- Go不支援泛型,只能用
interface{} 類比
- 返回的型別安全需要使用者自己保證,
.(type) 的類型必須匹配
interface{} 是運行時泛型,效能沒有編譯時間泛型高
由此可見,?: 不僅僅是一個簡單的三元運算式。其實它更像一個內建的泛型版的函數(因為運算式天生就是支援泛型的)。
期望未來的Go版本中,能完善對 ?: 三元運算式 和 編譯時間的泛型 的支援。
補充:
星星 同學的提示:可能會導致深入嵌套的濫用: c?d?e?0:1:2:3 。
因為三元運算式是一個運算式,必然是允許嵌套的。
不過我覺得嵌套不是問題的本質,函數也能導致嵌套的濫用。
但是不能因為濫用的行為來排斥有存在價值的文法(比如三元運算式)。