關(guān)于Explicit還是Implicit一直是編程語(yǔ)言中能讓程序員們干起架的爭(zhēng)議。那些聰明的老鳥(niǎo)總是覺(jué)得Implicit的規(guī)則讓他們能夠一目十行撼短,減少樣板代碼的羈絆。而很多時(shí)候挺勿,Implicit的很多規(guī)則會(huì)讓新手或者是合作開(kāi)發(fā)的搭檔痛苦不堪曲横。文章的標(biāo)題也寫(xiě)明了筆者的態(tài)度,顯式的在代碼之中指明自己的意圖不瓶,會(huì)讓程序更加明晰禾嫉。所以也借今天這篇文章,我們來(lái)聊聊Explicit關(guān)鍵字蚊丐。
1.隱式類類型轉(zhuǎn)換
好吧熙参,先看一段代碼:
(為了簡(jiǎn)單起見(jiàn),我這里就沒(méi)有重載<<操作符了)
class A {
public:
A(int s) {};
};
void printA(A a) {
cout << "hello" << endl;
}
int main() {
printA(10);
}
上面這段代碼是可以通過(guò)編譯運(yùn)行的吠撮,可能有些小伙伴會(huì)比較困惑尊惰,為蝦米這里printA函數(shù)明明需要接受的是一個(gè)A類型,但是傳入的一個(gè)int類型仍然能夠編譯通過(guò)泥兰。
這就被稱之為隱式類類型轉(zhuǎn)換弄屡,它存在于自定義的類構(gòu)造函數(shù)中。C++的編譯器會(huì)對(duì)只有一個(gè)參數(shù)的構(gòu)造函數(shù)也定義了一個(gè)隱式轉(zhuǎn)換鞋诗,將該構(gòu)造函數(shù)對(duì)應(yīng)數(shù)據(jù)類型的數(shù)據(jù)轉(zhuǎn)換為該類對(duì)象膀捷。也就是說(shuō),上段代碼其實(shí)可以翻譯成下面的代碼:
class A {
public:
A(int s) {};
};
void printA(A a) {
cout << "hello" << endl;
}
int main() {
printA(A(10));
}
這里10作為int類型的參數(shù)削彬,通過(guò)隱式的類類型轉(zhuǎn)換全庸,被默認(rèn)構(gòu)造了一個(gè)A類型的匿名對(duì)象秀仲,傳入了函數(shù)printA,所以代碼能夠正常的編譯運(yùn)行。顯然壶笼,這種類型的代碼是十分Confused神僵。所以我們來(lái)看看這么解決這個(gè)問(wèn)題的。
有一個(gè)折衷的解決方案覆劈,將代碼做下面的修改:
void printA(A &a) {
cout << "hello" << endl;
}
這里通過(guò)引用類型就可以避開(kāi)這個(gè)陷阱保礼,因?yàn)榫幾g器不會(huì)構(gòu)造這個(gè)匿名對(duì)象的引用,所以此時(shí)的代碼是無(wú)法通過(guò)編譯的责语。
顯然炮障,這個(gè)方案改變了我們不使用引用類型的初衷,我們看看C++有木有更加優(yōu)雅的解決方案坤候。
2.Explicit關(guān)鍵字
explicit主要用于"修飾"構(gòu)造函數(shù)胁赢,使得它不用于程序中需要通過(guò)此構(gòu)造函數(shù)進(jìn)行"隱式"轉(zhuǎn)換的情況。指定此關(guān)鍵字白筹,需要隱式轉(zhuǎn)換方可進(jìn)行的程序?qū)⒉荒芫幾g通過(guò)智末。
class A {
public:
explicit A(int s) {};
};
void printA(A a) {
cout << "hello" << endl;
}
int main() {
printA(10); //無(wú)法通過(guò)編譯
}
這里我們添加了explicit關(guān)鍵字,阻止了編譯器的隱式類類型轉(zhuǎn)換徒河,讓代碼更加明晰了吹害。當(dāng)然,我們這里是可以使用static_cast關(guān)鍵字可以顯式的類型轉(zhuǎn)換虚青,通過(guò)代碼的編譯。
int main() {
printA(static_cast<A>(32));
}
explicit關(guān)鍵字只對(duì)一個(gè)參數(shù)的構(gòu)造函數(shù)有效螺男,需要多個(gè)實(shí)參的構(gòu)造函數(shù)不能用于隱式類型轉(zhuǎn)換棒厘。
3.討論一下
Scala
類型系統(tǒng)幾乎是Scala之中最復(fù)雜的內(nèi)容,Scala設(shè)計(jì)的討巧之處下隧,是通過(guò)implicit關(guān)鍵字,顯式的指定了隱式類類型轉(zhuǎn)換奢人。雖然隱式類類型轉(zhuǎn)換減少了很多冗余的代碼,但是這樣的設(shè)計(jì)會(huì)降低代碼的可讀性淆院。Scala也一直因?yàn)榭勺x性被詬病何乎,所以這樣的設(shè)計(jì),見(jiàn)仁見(jiàn)智土辩。Golang
如果是接口interface與Python是類似的鴨子類型支救,不需要什么隱式轉(zhuǎn)換了。
而如果是struct類的話拷淘,那Golang就十分嚴(yán)格的執(zhí)行強(qiáng)類型的判斷各墨。不符合是不行的。Java
Java一直是拒絕這種Confuse做法的語(yǔ)言启涯,所以通過(guò)一大堆繁瑣的樣板代碼規(guī)避這樣的問(wèn)題贬堵。
“Explicit's better than implicit”恃轩。Explicit保證了代碼的可讀性和維護(hù)性。這點(diǎn)對(duì)于一個(gè)系統(tǒng)的工程性是很有幫助的黎做。Implicit的轉(zhuǎn)換容易帶來(lái)那種“看上去很美叉跛,但是非常容易出錯(cuò)”的 feature 。希望我們能夠告別對(duì)它的依賴蒸殿。