為什么 Go 不支持函數(shù)重載和缺省參數(shù)?
大家好,我是煎魚(yú)。
部分同學(xué)在初學(xué)習(xí) Go 語(yǔ)言時(shí),帶著其他語(yǔ)言的習(xí)慣,總是會(huì)有些不習(xí)慣,感覺(jué)非常不能理解,直打問(wèn)號(hào)。
其中一點(diǎn)就是問(wèn)到 “為什么 Go 語(yǔ)言不支持函數(shù)重載和缺省參數(shù)”,覺(jué)得使用起來(lái)很不方便,畢竟以前能省了定義不少東西。
為此,在這篇文章中煎魚(yú)就和大家一起來(lái)了解為什么,有又會(huì)怎么樣。
函數(shù)重載
函數(shù)重載(function overloading),也叫方法重載。是某些編程語(yǔ)言(如 C++、C#、Java、Swift、Kotlin 等)具有的一項(xiàng)特性。
該特性允許創(chuàng)建多個(gè)具有不同實(shí)現(xiàn)的同名函數(shù),對(duì)重載函數(shù)的調(diào)用會(huì)運(yùn)行其適用于調(diào)用上下文的具體實(shí)現(xiàn)。
從功能上來(lái)講,就是允許一個(gè)函數(shù)調(diào)用根據(jù)上下文執(zhí)行不同的方法,達(dá)到調(diào)用同一個(gè)函數(shù)名,執(zhí)行不同的方法。
一個(gè)簡(jiǎn)單的例子:
#include?
int?Volume(int?s)?{??//?立方體的體積。
??return?s?*?s?*?s;
}
double?Volume(double?r,?int?h)?{??//?圓柱體的體積。
??return?3.1415926?*?r?*?r?*?static_cast<double>(h);
}
long?Volume(long?l,?int?b,?int?h)?{??//?長(zhǎng)方體的體積。
??return?l?*?b?*?h;
}
int?main()?{
??std::cout?<10);
??std::cout?<2.5,?8);
??std::cout?<100l,?75,?15);
}
在上述例子中,實(shí)現(xiàn)了 3 個(gè)同名的 Volume 函數(shù),但是 3 個(gè)函數(shù)的入?yún)€(gè)數(shù)、類(lèi)型均不一樣,也代表了不同的實(shí)現(xiàn)目的。
在主函數(shù) main 中,傳入了不同的入?yún)ⅲ幾g器或運(yùn)行時(shí)再進(jìn)行內(nèi)部處理,從程序上來(lái)看達(dá)到了調(diào)用不同函數(shù)的目的。
這就是函數(shù)重載,一函數(shù)多形態(tài)。
參數(shù)默認(rèn)值
參數(shù)默認(rèn)值,又叫缺省參數(shù)。指的是允許程序員設(shè)定缺省參數(shù)并指定默認(rèn)值,當(dāng)調(diào)用該函數(shù)并未指定值時(shí),該缺省參數(shù)將為缺省值來(lái)使用。
一個(gè)簡(jiǎn)單的例子:
?int?my_func(int?a,?int?b,?int?c=12);
在上述例子中,函數(shù) my_func 一共有 3 個(gè)變量,分別是:a、b、c。變量 c 設(shè)置了缺省值,也就是 12。
其調(diào)用方式可以為:
?//?第一種調(diào)用方式
?result?=?my_func(1,?2,?3);
?//?第二種調(diào)用方式
?result?=?my_func(1,?2);
在第一種方式中,就會(huì)正常的傳入所有參數(shù)。在第二種方式,由于第三個(gè)參數(shù) c 并沒(méi)有傳遞,因此會(huì)直接使用缺省值 12。
這就是參數(shù)默認(rèn)值,也叫缺省參數(shù)。
為什么不支持
美好
從上述的功能特性介紹來(lái)看,似乎非常的不錯(cuò),能夠節(jié)省很多功夫。像是 Go 語(yǔ)言的 context 庫(kù)中的這些方法:
func?WithCancel(parent?Context)?(ctx?Context,?cancel?CancelFunc)
func?WithDeadline(parent?Context,?d?time.Time)?(Context,?CancelFunc)
func?WithTimeout(parent?Context,?timeout?time.Duration)?(Context,?CancelFunc)
要是有函數(shù)重載,直接就 WithXXX 就好了,只需要關(guān)注傳入的參數(shù)類(lèi)型,也不用 “記” 那么多個(gè)方法名了。
有同學(xué)說(shuō),有參數(shù)默認(rèn)值。那就可以直接設(shè)置在上面,作為 “最佳實(shí)踐” 給到使用函數(shù)的人,豈不美哉。那怎么 Go 語(yǔ)言就不支持呢?
細(xì)思
其實(shí)這和設(shè)計(jì)理念,和對(duì)程序的理解有關(guān)系。說(shuō)白了,就是你喜歡 “顯式”,還是 “隱喻”。
函數(shù)重載和參數(shù)默認(rèn)值,其實(shí)是不好的行為。調(diào)用者只看函數(shù)名字,可能沒(méi)法知道,你這個(gè)默認(rèn)值,又或是入?yún)⒉煌瑫?huì)調(diào)用的東西,會(huì)產(chǎn)生怎么樣的后果?
你可以觀察一下自己的行為。大部分人都會(huì)潛意識(shí)的追進(jìn)去看代碼,看看會(huì)調(diào)到哪,缺省值的作用是什么,以確保可控。
敲定
這細(xì)思的可能,在 Go 語(yǔ)言中是不被允許的。Go 語(yǔ)言的設(shè)計(jì)理念就是 “顯式大于隱喻”,追求明確,顯式。
在 Go FAQ 《Why does Go not support overloading of methods and operators?》有相關(guān)的解釋。
如下圖:

官方有明確提到兩個(gè)觀點(diǎn):
函數(shù)重載:擁有各種同名但不同簽名的方法有時(shí)是很有用的,但在實(shí)踐中也可能是混亂和脆弱的。 參數(shù)默認(rèn)值:操作符重載,似乎更像是一種便利,不是絕對(duì)的要求。沒(méi)有它,程序會(huì)更簡(jiǎn)單。
這就是為什么 Go 語(yǔ)言不支持的原因。
總結(jié)
在這篇文章中,我們介紹了業(yè)內(nèi)常見(jiàn)的編程語(yǔ)言的函數(shù)重載和參數(shù)默認(rèn)值的概念和使用方法。也結(jié)合了 Go 語(yǔ)言自身的設(shè)計(jì)理念,說(shuō)明了為什么不支持的原因。
你會(huì)希望 Go 語(yǔ)言支持這幾個(gè)特性功能嗎,歡迎在評(píng)論區(qū)留言討論和交流:)
參考
維基百科(函數(shù)重載和缺省值定義) Frequently Asked Questions (FAQ) 關(guān)注煎魚(yú),吸取他的知識(shí)???

你好,我是煎魚(yú),出版過(guò) Go 暢銷(xiāo)書(shū)《Go 語(yǔ)言編程之旅》,再到獲得 GOP(Go 領(lǐng)域最有觀點(diǎn)專(zhuān)家)榮譽(yù),點(diǎn)擊藍(lán)字查看我的出書(shū)之路。
日常分享高質(zhì)量文章,輸出 Go 面試、工作經(jīng)驗(yàn)、架構(gòu)設(shè)計(jì),加微信拉讀者交流群,和大家交流!
