Go 語(yǔ)言 Hello, World 的革命

2023-03-22 14:56 更新

原文鏈接:https://chai2010.cn/advanced-go-programming-book/ch1-basic/ch1-02-hello-revolution.html


1.2 Hello, World 的革命

在創(chuàng)世紀(jì)章節(jié)中我們簡(jiǎn)單介紹了 Go 語(yǔ)言的演化基因族譜,對(duì)其中來(lái)自于貝爾實(shí)驗(yàn)室的特有并發(fā)編程基因做了重點(diǎn)介紹,最后引出了 Go 語(yǔ)言版的“Hello, World”程序。其實(shí)“Hello, World”程序是展示各種語(yǔ)言特性的最好的例子,是通向該語(yǔ)言的一個(gè)窗口。這一節(jié)我們將沿著各個(gè)編程語(yǔ)言演化的時(shí)間軸,簡(jiǎn)單回顧下“Hello, World”程序是如何逐步演化到目前的 Go 語(yǔ)言形式、最終完成它的革命使命的。


圖 1-4 Go 語(yǔ)言并發(fā)演化歷史

1.2.1 B 語(yǔ)言 - Ken Thompson, 1972

首先是 B 語(yǔ)言,B 語(yǔ)言是 Go 語(yǔ)言之父貝爾實(shí)驗(yàn)室的 Ken Thompson 早年間開(kāi)發(fā)的一種通用的程序設(shè)計(jì)語(yǔ)言,設(shè)計(jì)目的是為了用于輔助 UNIX 系統(tǒng)的開(kāi)發(fā)。但是因?yàn)锽語(yǔ)言缺乏靈活的類型系統(tǒng)導(dǎo)致使用比較困難。后來(lái),Ken Thompson 的同事 Dennis Ritchie 以 B 語(yǔ)言為基礎(chǔ)開(kāi)發(fā)出了 C 語(yǔ)言,C 語(yǔ)言提供了豐富的類型,極大地增加了語(yǔ)言的表達(dá)能力。到目前為止它依然是世界上最常用的程序語(yǔ)言之一。而B(niǎo)語(yǔ)言自從被它取代之后,則就只存在于各種文獻(xiàn)之中,成為了歷史。

目前見(jiàn)到的 B 語(yǔ)言版本的“Hello World”,一般認(rèn)為是來(lái)自于 Brian W. Kernighan 編寫的 B 語(yǔ)言入門教程(Go 核心代碼庫(kù)中的第一個(gè)提交者名字正是 Brian W. Kernighan),程序如下:

main() {
    extrn a, b, c;
    putchar(a); putchar(b); putchar(c);
    putchar('!*n');
}
a 'hell';
b 'o, w';
c 'orld';

由于 B 語(yǔ)言缺乏靈活的數(shù)據(jù)類型,只能分別以 a、b、c 全局變量來(lái)定義要輸出的內(nèi)容,并且每個(gè)變量的長(zhǎng)度必須對(duì)齊到了 4 個(gè)字節(jié)(有一種寫匯編語(yǔ)言的感覺(jué))。然后通過(guò)多次調(diào)用 putchar 函數(shù)輸出字符,最后的 '!*n' 表示輸出一個(gè)換行的意思。

總體來(lái)說(shuō),B 語(yǔ)言簡(jiǎn)單,功能也比較簡(jiǎn)陋。

1.2.2 C 語(yǔ)言 - Dennis Ritchie, 1974 ~ 1989

C 語(yǔ)言是由 Dennis Ritchie 在 B 語(yǔ)言的基礎(chǔ)上改進(jìn)而來(lái),它增加了豐富的數(shù)據(jù)類型,并最終實(shí)現(xiàn)了用它重寫 UNIX 的偉大目標(biāo)。C 語(yǔ)言可以說(shuō)是現(xiàn)代 IT 行業(yè)最重要的軟件基石,目前主流的操作系統(tǒng)幾乎全部是由 C 語(yǔ)言開(kāi)發(fā)的,許多基礎(chǔ)系統(tǒng)軟件也是 C 語(yǔ)言開(kāi)發(fā)的。C 系家族的編程語(yǔ)言占據(jù)統(tǒng)治地位達(dá)幾十年之久,半個(gè)多世紀(jì)以來(lái)依然充滿活力。

在 Brian W. Kernighan 于 1974 年左右編寫的 C 語(yǔ)言入門教程中,出現(xiàn)了第一個(gè) C 語(yǔ)言版本的“Hello World”程序。這給后來(lái)大部分編程語(yǔ)言教程都以“Hello World”為第一個(gè)程序提供了慣例。第一個(gè) C 語(yǔ)言版本的“Hello World”程序如下:

main()
{
    printf("hello, world");
}

關(guān)于這個(gè)程序,有幾點(diǎn)需要說(shuō)明的:首先是 main 函數(shù)因?yàn)闆](méi)有明確返回值類型,默認(rèn)返回 int 類型;其次 printf 函數(shù)默認(rèn)不需要導(dǎo)入函數(shù)聲明即可以使用;最后 main 沒(méi)有明確返回語(yǔ)句,但默認(rèn)返回 0 值。在這個(gè)程序出現(xiàn)時(shí),C 語(yǔ)言還遠(yuǎn)未標(biāo)準(zhǔn)化,我們看到的是上古時(shí)代的 C 語(yǔ)言語(yǔ)法:函數(shù)不用寫返回值,函數(shù)參數(shù)也可以忽略,使用 printf 時(shí)不需要包含頭文件等。

這個(gè)例子同樣出現(xiàn)在了 1978 年出版的《C 程序設(shè)計(jì)語(yǔ)言》第一版中,作者正是 Brian W. Kernighan 和 Dennis M. Ritchie(簡(jiǎn)稱 K&R)。書(shū)中的“Hello World”末尾增加了一個(gè)換行輸出:

main()
{
    printf("hello, world\n");
}

這個(gè)例子在字符串末尾增加了一個(gè)換行,C 語(yǔ)言的 \n 換行比 B 語(yǔ)言的 '!*n' 換行看起來(lái)要簡(jiǎn)潔了一些。

在 K&R 的教程面世 10 年之后的 1988 年,《C 程序設(shè)計(jì)語(yǔ)言》第二版終于出版了。此時(shí) ANSI C 語(yǔ)言的標(biāo)準(zhǔn)化草案已經(jīng)初步完成,但正式版本的文檔尚未發(fā)布。不過(guò)書(shū)中的“Hello World”程序根據(jù)新的規(guī)范增加了 #include <stdio.h> 頭文件包含語(yǔ)句,用于包含printf函數(shù)的聲明(新的 C89 標(biāo)準(zhǔn)中,僅僅是針對(duì)printf函數(shù)而言,依然可以不用聲明函數(shù)而直接使用)。

#include <stdio.h>

main()
{
    printf("hello, world\n");
}

然后到了 1989 年,ANSI C 語(yǔ)言第一個(gè)國(guó)際標(biāo)準(zhǔn)發(fā)布,一般被稱為 C89。C89 是流行最廣泛的一個(gè) C 語(yǔ)言標(biāo)準(zhǔn),目前依然被大量使用?!禖 程序設(shè)計(jì)語(yǔ)言》第二版的也再次印刷新版本,并針對(duì)新發(fā)布的 C89 規(guī)范建議,給 main 函數(shù)的參數(shù)增加了 void 輸入?yún)?shù)說(shuō)明,表示沒(méi)有輸入?yún)?shù)的意思。

#include <stdio.h>

main(void)
{
    printf("hello, world\n");
}

至此,C 語(yǔ)言本身的進(jìn)化基本完成。后面的 C92、C99、C11 都只是針對(duì)一些語(yǔ)言細(xì)節(jié)做了完善。因?yàn)楦鞣N歷史因素, C89 依然是使用最廣泛的標(biāo)準(zhǔn)。

1.2.3 Newsqueak - Rob Pike, 1989

Newsqueak 是 Rob Pike 發(fā)明的老鼠語(yǔ)言的第二代,是他用于實(shí)踐 CSP 并發(fā)編程模型的戰(zhàn)場(chǎng)。Newsqueak 是新的 squeak 語(yǔ)言的意思,其中 squeak 是老鼠吱吱吱的叫聲,也可以看作是類似鼠標(biāo)點(diǎn)擊的聲音。Squeak 是一個(gè)提供鼠標(biāo)和鍵盤事件處理的編程語(yǔ)言,Squeak語(yǔ)言的管道是靜態(tài)創(chuàng)建的。改進(jìn)版的 Newsqueak 語(yǔ)言則提供了類似 C 語(yǔ)言語(yǔ)句和表達(dá)式的語(yǔ)法和類似 Pascal 語(yǔ)言的推導(dǎo)語(yǔ)法。Newsqueak 是一個(gè)帶自動(dòng)垃圾回收的純函數(shù)式語(yǔ)言,它再次針對(duì)鍵盤、鼠標(biāo)和窗口事件管理。但是在 Newsqueak 語(yǔ)言中管道是動(dòng)態(tài)創(chuàng)建的,屬于第一類值,因此可以保存到變量中。

Newsqueak 類似腳本語(yǔ)言,內(nèi)置了一個(gè) ?print ?函數(shù),它的“Hello World”程序看不出什么特色:

print("Hello,", "World", "\n");

從上面的程序中,除了猜測(cè) print 函數(shù)可以支持多個(gè)參數(shù)外,我們很難看到 Newsqueak 語(yǔ)言相關(guān)的特性。由于 Newsqueak 語(yǔ)言和 Go 語(yǔ)言相關(guān)的特性主要是并發(fā)和管道。因此,我們這里通過(guò)一個(gè)并發(fā)版本的“素?cái)?shù)篩”算法來(lái)略窺 Newsqueak 語(yǔ)言的特性?!八?cái)?shù)篩”的原理如圖:


圖 1-5 素?cái)?shù)篩

Newsqueak 語(yǔ)言并發(fā)版本的“素?cái)?shù)篩”程序如下:

// 向管道輸出從 2 開(kāi)始的自然數(shù)序列
counter := prog(c:chan of int) {
    i := 2;
    for(;;) {
        c <-= i++;
    }
};

// 針對(duì) listen 管道獲取的數(shù)列,過(guò)濾掉是 prime 倍數(shù)的數(shù)
// 新的序列輸出到 send 管道
filter := prog(prime:int, listen, send:chan of int) {
    i:int;
    for(;;) {
        if((i = <-listen)%prime) {
            send <-= i;
        }
    }
};

// 主函數(shù)
// 每個(gè)管道第一個(gè)流出的數(shù)必然是素?cái)?shù)
// 然后基于這個(gè)新的素?cái)?shù)構(gòu)建新的素?cái)?shù)過(guò)濾器
sieve := prog() of chan of int {
    c := mk(chan of int);
    begin counter(c);
    prime := mk(chan of int);
    begin prog(){
        p:int;
        newc:chan of int;
        for(;;){
            prime <-= p =<- c;
            newc = mk();
            begin filter(p, c, newc);
            c = newc;
        }
    }();
    become prime;
};

// 啟動(dòng)素?cái)?shù)篩
prime := sieve();

其中 counter 函數(shù)用于向管道輸出原始的自然數(shù)序列,每個(gè) filter 函數(shù)對(duì)象則對(duì)應(yīng)每一個(gè)新的素?cái)?shù)過(guò)濾管道,這些素?cái)?shù)過(guò)濾管道根據(jù)當(dāng)前的素?cái)?shù)篩子將輸入管道流入的數(shù)列篩選后重新輸出到輸出管道。mk(chan of int) 用于創(chuàng)建管道,類似 Go 語(yǔ)言的 make(chan int) 語(yǔ)句;begin filter(p, c, newc) 關(guān)鍵字啟動(dòng)素?cái)?shù)篩的并發(fā)體,類似 Go 語(yǔ)言的 go filter(p, c, newc) 語(yǔ)句;become 用于返回函數(shù)結(jié)果,類似 return 語(yǔ)句。

Newsqueak 語(yǔ)言中并發(fā)體和管道的語(yǔ)法和 Go 語(yǔ)言已經(jīng)比較接近了,后置的類型聲明和 Go 語(yǔ)言的語(yǔ)法也很相似。

1.2.4 Alef - Phil Winterbottom, 1993

在 Go 語(yǔ)言出現(xiàn)之前,Alef 語(yǔ)言是作者心中比較完美的并發(fā)語(yǔ)言,Alef 語(yǔ)法和運(yùn)行時(shí)基本是無(wú)縫兼容 C 語(yǔ)言。Alef 語(yǔ)言中的對(duì)線程和進(jìn)程的并發(fā)體都提供了支持,其中 proc receive(c) 用于啟動(dòng)一個(gè)進(jìn)程,task receive(c) 用于啟動(dòng)一個(gè)線程,它們之間通過(guò)管道 c 進(jìn)行通訊。不過(guò)由于 Alef 缺乏內(nèi)存自動(dòng)回收機(jī)制,導(dǎo)致并發(fā)體的內(nèi)存資源管理異常復(fù)雜。而且 Alef 語(yǔ)言只在 Plan9 系統(tǒng)中提供過(guò)短暫的支持,其它操作系統(tǒng)并沒(méi)有實(shí)際可以運(yùn)行的 Alef 開(kāi)發(fā)環(huán)境。而且 Alef 語(yǔ)言只有《Alef 語(yǔ)言規(guī)范》和《Alef 編程向?qū)А穬蓚€(gè)公開(kāi)的文檔,因此在貝爾實(shí)驗(yàn)室之外關(guān)于 Alef 語(yǔ)言的討論并不多。

由于 Alef 語(yǔ)言同時(shí)支持進(jìn)程和線程并發(fā)體,而且在并發(fā)體中可以再次啟動(dòng)更多的并發(fā)體,導(dǎo)致了 Alef 的并發(fā)狀態(tài)會(huì)異常復(fù)雜。同時(shí) Alef 沒(méi)有自動(dòng)垃圾回收機(jī)制(Alef 因?yàn)楸A舻?C 語(yǔ)言靈活的指針特性,也導(dǎo)致了自動(dòng)垃圾回收機(jī)制實(shí)現(xiàn)比較困難),各種資源充斥于不同的線程和進(jìn)程之間,導(dǎo)致并發(fā)體的內(nèi)存資源管理異常復(fù)雜。Alef 語(yǔ)言全部繼承了 C 語(yǔ)言的語(yǔ)法,可以認(rèn)為是增強(qiáng)了并發(fā)語(yǔ)法的 C 語(yǔ)言。下圖是 Alef 語(yǔ)言文檔中展示的一個(gè)可能的并發(fā)體狀態(tài):


圖 1-6 Alef 并發(fā)模型

Alef 語(yǔ)言并發(fā)版本的“Hello World”程序如下:

#include <alef.h>

void receive(chan(byte*) c) {
    byte *s;
    s = <- c;
    print("%s\n", s);
    terminate(nil);
}

void main(void) {
    chan(byte*) c;
    alloc c;
    proc receive(c);
    task receive(c);
    c <- = "hello proc or task";
    c <- = "hello proc or task";
    print("done\n");
    terminate(nil);
}

程序開(kāi)頭的 #include <alef.h> 語(yǔ)句用于包含 Alef 語(yǔ)言的運(yùn)行時(shí)庫(kù)。receive 是一個(gè)普通函數(shù),程序中用作每個(gè)并發(fā)體的入口函數(shù);main 函數(shù)中的 alloc c 語(yǔ)句先創(chuàng)建一個(gè) chan(byte*) 類型的管道,類似 Go 語(yǔ)言的 make(chan []byte) 語(yǔ)句;然后分別以進(jìn)程和線程的方式啟動(dòng) receive 函數(shù);啟動(dòng)并發(fā)體之后,main 函數(shù)向 c 管道發(fā)送了兩個(gè)字符串?dāng)?shù)據(jù); 而進(jìn)程和線程狀態(tài)運(yùn)行的 receive 函數(shù)會(huì)以不確定的順序先后從管道收到數(shù)據(jù)后,然后分別打印字符串;最后每個(gè)并發(fā)體都通過(guò)調(diào)用 terminate(nil) 來(lái)結(jié)束自己。

Alef 的語(yǔ)法和 C 語(yǔ)言基本保持一致,可以認(rèn)為它是在 C 語(yǔ)言的語(yǔ)法基礎(chǔ)上增加了并發(fā)編程相關(guān)的特性,可以看作是另一個(gè)維度的 C++ 語(yǔ)言。

1.2.5 Limbo - Sean Dorward, Phil Winterbottom, Rob Pike, 1995

Limbo(地獄)是用于開(kāi)發(fā)運(yùn)行在小型計(jì)算機(jī)上的分布式應(yīng)用的編程語(yǔ)言,它支持模塊化編程,編譯期和運(yùn)行時(shí)的強(qiáng)類型檢查,進(jìn)程內(nèi)基于具有類型的通信管道,原子性垃圾收集和簡(jiǎn)單的抽象數(shù)據(jù)類型。Limbo 被設(shè)計(jì)為:即便是在沒(méi)有硬件內(nèi)存保護(hù)的小型設(shè)備上,也能安全運(yùn)行。Limbo 語(yǔ)言主要運(yùn)行在 Inferno 系統(tǒng)之上。

Limbo 語(yǔ)言版本的“Hello World”程序如下:

implement Hello;

include "sys.m"; sys: Sys;
include "draw.m";

Hello: module
{
    init: fn(ctxt: ref Draw->Context, args: list of string);
};

init(ctxt: ref Draw->Context, args: list of string)
{
    sys = load Sys Sys->PATH;
    sys->print("hello, world\n");
}

從這個(gè)版本的“Hello World”程序中,我們已經(jīng)可以發(fā)現(xiàn)很多 Go 語(yǔ)言特性的雛形。第一句 implement Hello; 基本對(duì)應(yīng) Go 語(yǔ)言的 package Hello 包聲明語(yǔ)句。然后是 include "sys.m"; sys: Sys; 和 include "draw.m"; 語(yǔ)句用于導(dǎo)入其它的模塊,類似 Go 語(yǔ)言的 import "sys" 和 import "draw" 語(yǔ)句。然后 Hello 包模塊還提供了模塊初始化函數(shù) init,并且函數(shù)的參數(shù)的類型也是后置的,不過(guò) Go 語(yǔ)言的初始化函數(shù)是沒(méi)有參數(shù)的。

1.2.6 Go 語(yǔ)言 - 2007~2009

貝爾實(shí)驗(yàn)室后來(lái)經(jīng)歷了多次動(dòng)蕩,包括 Ken Thompson 在內(nèi)的 Plan9 項(xiàng)目原班人馬最終加入了 Google 公司。在發(fā)明 Limbo 等前輩語(yǔ)言誕生十多年之后,在 2007 年底,Go 語(yǔ)言三個(gè)最初的作者因?yàn)榕既坏囊蛩鼐奂揭黄鹋?C++(傳說(shuō)是 C++ 語(yǔ)言的布道師在 Google 公司到處鼓吹的 C++11 各種牛逼特性徹底惹惱了他們),他們終于抽出了 20% 的自由時(shí)間創(chuàng)造了 Go 語(yǔ)言。最初的 Go 語(yǔ)言規(guī)范從 2008 年 3 月開(kāi)始編寫,最初的 Go 程序也是直接編譯到 C 語(yǔ)言然后再二次編譯為機(jī)器碼。到了 2008 年 5 月,Google 公司的領(lǐng)導(dǎo)們終于發(fā)現(xiàn)了 Go 語(yǔ)言的巨大潛力,從而開(kāi)始全力支持這個(gè)項(xiàng)目(Google 的創(chuàng)始人甚至還貢獻(xiàn)了func關(guān)鍵字),讓他們可以將全部工作時(shí)間投入到 Go 語(yǔ)言的設(shè)計(jì)和開(kāi)發(fā)中。在 Go 語(yǔ)言規(guī)范初版完成之后,Go 語(yǔ)言的編譯器終于可以直接生成機(jī)器碼了。

1.2.6.1 hello.go - 2008 年 6 月

package main

func main() int {
    print "hello, world\n";
    return 0;
}

這是初期 Go 語(yǔ)言程序正式開(kāi)始測(cè)試的版本。其中內(nèi)置的用于調(diào)試的 print 語(yǔ)句已經(jīng)存在,不過(guò)是以命令的方式使用。入口 main 函數(shù)還和 C 語(yǔ)言中的 main 函數(shù)一樣返回 int 類型的值,而且需要 return 顯式地返回值。每個(gè)語(yǔ)句末尾的分號(hào)也還存在。

1.2.6.2 hello.go - 2008 年 6 月 27 日

package main

func main() {
    print "hello, world\n";
}

入口函數(shù) main 已經(jīng)去掉了返回值,程序默認(rèn)通過(guò)隱式調(diào)用 exit(0) 來(lái)返回。Go 語(yǔ)言朝著簡(jiǎn)單的方向逐步進(jìn)化。

1.2.6.3 hello.go - 2008 年 8 月 11 日

package main

func main() {
    print("hello, world\n");
}

用于調(diào)試的內(nèi)置的 print 由開(kāi)始的命令改為普通的內(nèi)置函數(shù),使得語(yǔ)法更加簡(jiǎn)單一致。

1.2.6.4 hello.go - 2008 年 10 月 24 日

package main

import "fmt"

func main() {
    fmt.printf("hello, world\n");
}

作為 C 語(yǔ)言中招牌的 printf 格式化函數(shù)已經(jīng)移植了到了 Go 語(yǔ)言中,函數(shù)放在 fmt 包中(fmt 是格式化單詞 format 的縮寫)。不過(guò) printf 函數(shù)名的開(kāi)頭字母依然是小寫字母,采用大寫字母表示導(dǎo)出的特性還沒(méi)有出現(xiàn)。

1.2.6.5 hello.go - 2009年1月15日

package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n");
}

Go 語(yǔ)言開(kāi)始采用是否大小寫首字母來(lái)區(qū)分符號(hào)是否可以被導(dǎo)出。大寫字母開(kāi)頭表示導(dǎo)出的公共符號(hào),小寫字母開(kāi)頭表示包內(nèi)部的私有符號(hào)。國(guó)內(nèi)用戶需要注意的是,漢字中沒(méi)有大小寫字母的概念,因此以漢字開(kāi)頭的符號(hào)目前是無(wú)法導(dǎo)出的(針對(duì)問(wèn)題中國(guó)用戶已經(jīng)給出相關(guān)建議,等 Go2 之后或許會(huì)調(diào)整對(duì)漢字的導(dǎo)出規(guī)則)。

1.2.6.7 hello.go - 2009 年 12 月 11 日

package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

Go 語(yǔ)言終于移除了語(yǔ)句末尾的分號(hào)。這是 Go 語(yǔ)言在 2009 年 11 月 10 號(hào)正式開(kāi)源之后第一個(gè)比較重要的語(yǔ)法改進(jìn)。從 1978 年 C 語(yǔ)言教程第一版引入的分號(hào)分割的規(guī)則到現(xiàn)在,Go 語(yǔ)言的作者們花了整整 32 年終于移除了語(yǔ)句末尾的分號(hào)。在這 32 年的演化的過(guò)程中必然充滿了各種八卦故事,我想這一定是 Go 語(yǔ)言設(shè)計(jì)者深思熟慮的結(jié)果(現(xiàn)在 Swift 等新的語(yǔ)言也是默認(rèn)忽略分號(hào)的,可見(jiàn)分號(hào)確實(shí)并不是那么的重要)。

1.2.7 你好, 世界! - V2.0

在經(jīng)過(guò)半個(gè)世紀(jì)的涅槃重生之后,Go 語(yǔ)言不僅僅打印出了 Unicode 版本的“Hello, World”,而且可以方便地向全球用戶提供打印服務(wù)。下面版本通過(guò) http 服務(wù)向每個(gè)訪問(wèn)的客戶端打印中文的“你好, 世界!”和當(dāng)前的時(shí)間信息。

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    fmt.Println("Please visit http://127.0.0.1:12345/")
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        s := fmt.Sprintf("你好, 世界! -- Time: %s", time.Now().String())
        fmt.Fprintf(w, "%v\n", s)
        log.Printf("%v\n", s)
    })
    if err := http.ListenAndServe(":12345", nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

我們通過(guò)Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)自帶的 net/http 包構(gòu)造了一個(gè)獨(dú)立運(yùn)行的 http 服務(wù)。其中 http.HandleFunc("/", ...) 針對(duì) / 根路徑請(qǐng)求注冊(cè)了響應(yīng)處理函數(shù)。在響應(yīng)處理函數(shù)中,我們依然使用 fmt.Fprintf 格式化輸出函數(shù)實(shí)現(xiàn)了通過(guò) http 協(xié)議向請(qǐng)求的客戶端打印格式化的字符串,同時(shí)通過(guò)標(biāo)準(zhǔn)庫(kù)的日志包在服務(wù)器端也打印相關(guān)字符串。最后通過(guò) http.ListenAndServe 函數(shù)調(diào)用來(lái)啟動(dòng) http 服務(wù)。

至此,Go 語(yǔ)言終于完成了從單機(jī)單核時(shí)代的 C 語(yǔ)言到 21 世紀(jì)互聯(lián)網(wǎng)時(shí)代多核環(huán)境的通用編程語(yǔ)言的蛻變。



以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)