漫話:如何給女朋友解釋什么是語(yǔ)法糖?









語(yǔ)法糖(Syntactic sugar),也譯為糖衣語(yǔ)法,是由英國(guó)計(jì)算機(jī)科學(xué)家Peter J. Landin發(fā)明的一個(gè)技術(shù)術(shù)語(yǔ),指在計(jì)算機(jī)語(yǔ)言中添加的某種語(yǔ)法,這種語(yǔ)法對(duì)語(yǔ)言的功能并沒(méi)有影響,但是更方便程序員使用。
類(lèi)比一下就像我們?nèi)粘J褂玫囊恍┛s寫(xiě)、別稱或者是"黑話"、"暗語(yǔ)"等。都是用一種更加簡(jiǎn)練的語(yǔ)言表達(dá)復(fù)雜的含義。
如我們有人說(shuō)"基操勿6",直意為“不要大驚小怪,這只是基本操作”,表現(xiàn)一種低調(diào)的得意。
當(dāng)我們形容一個(gè)妹子的時(shí)候可以說(shuō)她是"可鹽可甜"等等的。

通過(guò)使用這些暗語(yǔ)、黑話,可以起到很多作用,如更加簡(jiǎn)潔、更加自然、效率高、錯(cuò)誤少等。
而在編程語(yǔ)言中引入語(yǔ)法糖,在使用上同樣可以起到使代碼更加簡(jiǎn)潔、提升代碼可讀性、提升編程效率、降低程序出現(xiàn)錯(cuò)誤的概率等。
有了暗語(yǔ)、黑話,可以讓人們交流更加順暢,有了語(yǔ)法糖,可以讓程序員寫(xiě)代碼更加爽。是一個(gè)道理。




就像我們?nèi)粘Uf(shuō)的一些"暗語(yǔ)"、"黑話",這些被發(fā)明出來(lái)是方便人們使用的,但是并不是所有人都能看得懂。
在看得懂的人之間使用的話是很方便的,但是如果有人不懂的話,就需要解釋給他們聽(tīng)。
同理,語(yǔ)法糖是編程語(yǔ)言中增加的一些語(yǔ)法特性,目的是方便開(kāi)發(fā)人員的使用,拿Java語(yǔ)言舉例,雖然Java中有很多語(yǔ)法糖,但是Java虛擬機(jī)并不支持這些語(yǔ)法糖,所以這些語(yǔ)法糖在編譯階段就會(huì)被還原成簡(jiǎn)單的基礎(chǔ)語(yǔ)法結(jié)構(gòu),這樣才能被虛擬機(jī)識(shí)別,這個(gè)過(guò)程就是解語(yǔ)法糖。
如果看過(guò)Java虛擬機(jī)的源碼,就會(huì)發(fā)現(xiàn)在編譯過(guò)程中有一個(gè)重要的步驟就是調(diào)用desugar(),這個(gè)方法就是負(fù)責(zé)解語(yǔ)法糖的實(shí)現(xiàn)。
通常情況下,我們可以通過(guò)反編譯(漫話:如何給女朋友解釋什么是編譯與反編譯)的方式學(xué)習(xí)語(yǔ)法糖具體是如何實(shí)現(xiàn)的。




Java作為一種高級(jí)語(yǔ)言,是有很多語(yǔ)法糖的,而且從Java 7開(kāi)始,幾個(gè)重要的版本中提供的新特性都是和語(yǔ)法糖有關(guān)系的。
逐漸的,Java已經(jīng)從一個(gè)低糖語(yǔ)言變成一個(gè)高糖語(yǔ)言了。
如switch支持枚舉及字符串、泛型、條件編譯、斷言、可變參數(shù)、自動(dòng)裝箱/拆箱、枚舉、內(nèi)部類(lèi)、增強(qiáng)for循環(huán)、try-with-resources語(yǔ)句、lambda表達(dá)式等。
還有JDK 10中的局部變量類(lèi)型推斷、JDK 13中的文本塊(Text Blocks),其實(shí)本質(zhì)上都是語(yǔ)法糖。
關(guān)于Java中的語(yǔ)法糖,Hollis大神寫(xiě)過(guò)很多文章深入的介紹過(guò)他們的原理,如《不了解這12個(gè)語(yǔ)法糖,別說(shuō)你會(huì)Java》、《我反編譯了Java 10的本地變量類(lèi)型推斷》等。
摘取一段關(guān)于switch對(duì)String的支持的分析過(guò)程如下:
Java中的swith自身原本就支持基本類(lèi)型。比如int、char等。對(duì)于int類(lèi)型,直接進(jìn)行數(shù)值的比較。對(duì)于char類(lèi)型則是比較其ascii碼。
所以,對(duì)于編譯器來(lái)說(shuō),switch中其實(shí)只能使用整型,任何類(lèi)型的比較都要轉(zhuǎn)換成整型。比如byte。short,char(ackii碼是整型)以及int。
看下switch對(duì)String得支持,有以下代碼:
public?class?switchDemoString?{
????public?static?void?main(String[]?args)?{
????????String?str?=?"world";
????????switch?(str)?{
????????case?"hello":
????????????System.out.println("hello");
????????????break;
????????case?"world":
????????????System.out.println("world");
????????????break;
????????default:
????????????break;
????????}
????}
}
反編譯后內(nèi)容如下:
public?class?switchDemoString
{
????public?switchDemoString()
????{
????}
????public?static?void?main(String?args[])
????{
????????String?str?=?"world";
????????String?s;
????????switch((s?=?str).hashCode())
????????{
????????default:
????????????break;
????????case?99162322:
????????????if(s.equals("hello"))
????????????????System.out.println("hello");
????????????break;
????????case?113318802:
????????????if(s.equals("world"))
????????????????System.out.println("world");
????????????break;
????????}
????}
}
看到邊以后的代碼,我們就能發(fā)現(xiàn):字符串的switch是通過(guò)equals()和hashCode()方法來(lái)實(shí)現(xiàn)的。
其他語(yǔ)法糖就不在這里詳細(xì)介紹了,感興趣的可以到H大的文章中學(xué)習(xí)下,總之學(xué)習(xí)思路都很類(lèi)似,就是通過(guò)反編譯的方式了解解糖后的代碼或者字節(jié)碼是怎樣的。




