也就是俗稱的“騙你”學(xué)Go語言系列。

這是一個(gè)適合閱讀的系列,我希" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運(yùn)營 > 從0開始Go語言-用Golang搭建網(wǎng)站(無依賴)

從0開始Go語言-用Golang搭建網(wǎng)站(無依賴)

時(shí)間:2023-06-02 01:39:01 | 來源:網(wǎng)站運(yùn)營

時(shí)間:2023-06-02 01:39:01 來源:網(wǎng)站運(yùn)營

從0開始Go語言-用Golang搭建網(wǎng)站(無依賴):

實(shí)踐是最好的學(xué)習(xí)方式-零基礎(chǔ)通過開發(fā)Web服務(wù)學(xué)習(xí)Go語言

本文適合有一定編程基礎(chǔ),但是沒有Go語言基礎(chǔ)的同學(xué)。

也就是俗稱的“騙你”學(xué)Go語言系列。

這是一個(gè)適合閱讀的系列,我希望您能夠在車上、廁所、餐廳都閱讀它,涉及代碼的部分也是精簡而實(shí)用的。

學(xué)習(xí)需要?jiǎng)訖C(jī)

Go語言能干什么?為什么要學(xué)習(xí)Go語言?

本系列文章,將會(huì)以編程開發(fā)中需求最大、應(yīng)用最廣的Web開發(fā)為例,一步一步的學(xué)習(xí)Go語言。當(dāng)看完本系列,您能夠清晰的了解Go語言Web開發(fā)的基本原理,您會(huì)驚嘆于Go語言的簡潔、高效和新鮮。

結(jié)果反饋才能讓你記住

《刻意練習(xí)》一書中說,學(xué)習(xí)需要及時(shí)反饋結(jié)果,才能提高學(xué)習(xí)體驗(yàn)。

本系列文章的每一節(jié),都會(huì)包含一段可運(yùn)行的有效代碼,跟著內(nèi)容一步一步操作,你可以在你自己的計(jì)算機(jī)上體驗(yàn)每一句代碼的作用。

不要學(xué)習(xí)不需要的東西

文章圍繞范例為核心,介紹知識(shí)點(diǎn)。文中不羅列語法和關(guān)鍵字,當(dāng)您還不知道它們用來干什么時(shí),反而會(huì)干擾您的注意力。

希望您在閱讀本系列文章后,對(duì)Go語言產(chǎn)生更多的學(xué)習(xí)欲望,成為一名合格的Gopher

Gopher:原譯是囊地鼠,也就是Go語言Logo的那個(gè)小可愛;這里特指Go程序員給自己的昵稱。

如何10分鐘搭建Go開發(fā)環(huán)境

1.下載Go語言安裝文件

訪問Go語言官方網(wǎng)站下載頁面:

https://golang.org/dl

可以看到官網(wǎng)提供了Microsoft Windows、Apple MacOS、Linux和Source下載。

直接下載對(duì)應(yīng)操作系統(tǒng)的安裝包。

2.和其他軟件一樣,根據(jù)提示安裝

3.配置環(huán)境變量

在正式使用Go編寫代碼之前,還有一個(gè)重要的“環(huán)境變量”需要配置:“$GOPATH”

GOPATH環(huán)境變量指定工作區(qū)的位置。如果沒有設(shè)置GOPATH,則假定在Unix系統(tǒng)上為$HOME/go,在Windows上為 %USERPROFILE%/go。如果要將自定義位置用作工作空間,可以設(shè)置GOPATH環(huán)境變量。
GOPATH環(huán)境變量是用于設(shè)置Go編譯可以執(zhí)行文件、包源碼以及依賴包所必要的工作目錄路徑,Go1.11后,新的木塊管理雖然可以不再依賴 $GOPATH/src,但是依然需要使用 $GOPATH/pkg 路徑來保存依賴包。

首先,創(chuàng)建好一個(gè)目錄用作GOPATH目錄

然后設(shè)置環(huán)境變量 GOPATH:

Linux & MacOS:


導(dǎo)入環(huán)境變量

$ export GOPATH=$YOUR_PATH/go

保存環(huán)境變量

$ source ~/.bash_profile

Windows:


控制面板->系統(tǒng)->高級(jí)系統(tǒng)設(shè)置->高級(jí)->環(huán)境變量設(shè)置




GOPATH所指定的目錄會(huì)生成3個(gè)子目錄:

4.檢查環(huán)境

打開命令行工具,運(yùn)行

$ go env

如果你看到類似這樣的結(jié)果,說明Go語言環(huán)境安裝完成.

GOARCH="amd64"GOBIN=""GOCACHE="/Users/zeta/Library/Caches/go-build"GOEXE=""GOFLAGS=""GOHOSTARCH="amd64"GOHOSTOS="darwin"GOOS="darwin"GOPATH="/Users/zeta/workspace/go"GOPROXY="https://goproxy.io"GORACE=""GOROOT="/usr/local/go"GOTMPDIR=""GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"GCCGO="gccgo"CC="clang"CXX="clang++"CGO_ENABLED="1"GOMOD=""CGO_CFLAGS="-g -O2"CGO_CPPFLAGS=""CGO_CXXFLAGS="-g -O2"CGO_FFLAGS="-g -O2"CGO_LDFLAGS="-g -O2"PKG_CONFIG="pkg-config"GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/7v/omg2000000000000019/T/go-build760324613=/tmp/go-build -gno-record-gcc-switches -fno-common"

5.選擇一款趁手的編輯器或IDE

現(xiàn)在很多通用的編輯器或IDE都支持Go語言比如

Go語言專用的IDE有

專用的IDE無論是配置和使用都比通用編輯器/IDE的簡單許多,但是我還是推薦大家使用通用編輯器/IDE,因?yàn)樵陂_發(fā)過程中肯定會(huì)需要編寫一些其他語言的程序或腳本,專用IDE在其他語言編寫方面較弱,來回切換不同的編輯器/IDE窗口會(huì)很低效。

另外,專用IDE提供很多高效的工具,在編譯、調(diào)試方面都很方便,但是學(xué)習(xí)階段,建議大家手動(dòng)執(zhí)行命令編譯、調(diào)試,有利于掌握Go語言。

四行代碼的Hello World!所能表達(dá)出來的核心

命令行代碼僅適用于Linux和MacOS系統(tǒng),Windows根據(jù)說明在視窗下操作即可。

1.創(chuàng)建項(xiàng)目

創(chuàng)建一個(gè)文件夾,進(jìn)入該文件夾

$ mkdir gowebserver && cd gowebserver

新建一個(gè)文件 main.go

$ touch main.go

2. 用編輯器打開文件,并輸入以下代碼:

package mainimport "fmt"func main() { fmt.Println("Hello, 世界")}

3.打開命令行終端,輸入以下命令

$ go run main.go

看到終端會(huì)輸出:

Hello, 世界

第一個(gè)Go代碼就完成了

這是一個(gè)很簡單的Hello World,但是包含了Go語言編程的許多核心元素,接下來就詳細(xì)講解。

解讀知識(shí)點(diǎn): 包 與 函數(shù)

package申明包 & import導(dǎo)入包

Go程序是由包構(gòu)成的。

代碼的第一行, 申明程序自己的包,用 package 關(guān)鍵字。package關(guān)鍵字必須是第一行出現(xiàn)的代碼。

范例代碼中,申明的本包名 main

在代碼中第二行, 導(dǎo)入“fmt”包, 使用 import 關(guān)鍵字。默認(rèn)情況下,導(dǎo)入包的包名與導(dǎo)入路徑的最后一個(gè)元素一致,例如 import "math/rand",在代碼中使用這個(gè)包時(shí),直接使用rand,例如 rand.New()

導(dǎo)入包的寫法可以多行,也可以“分組”, 例如:

import "fmt"import "math/rand"或者 分組

import ( "fmt" "math/rand")
fmt包是Go語言內(nèi)建的包,作用是輸出打印。

func關(guān)鍵字:定義函數(shù)

func是function的縮寫, 在Go語言中是定義函數(shù)的關(guān)鍵字。

func定義函數(shù)的格式為:

func 函數(shù)名(參數(shù)1 類型,參數(shù)2 類型){ 函數(shù)體}本例中定義了一個(gè)main函數(shù)。main函數(shù)沒有參數(shù)。
然后在main函數(shù)體里調(diào)用fmt包的Println函數(shù),在控制臺(tái)輸出字符串 “Hello, 世界”

所有Go語言的程序的入口都是main包下的main函數(shù) main.main(),所以每一個(gè)可執(zhí)行的Go程序都應(yīng)該有一個(gè)main包和一個(gè)main函數(shù)。

我們已經(jīng)介紹了九牛一毛中的一毛,接下來正式通過搭建一個(gè)簡單的Web服務(wù)學(xué)習(xí)Go語言

0依賴,創(chuàng)建一個(gè)Web服務(wù)

先從代碼開始

打開之前創(chuàng)建好的main.go文件,修改代碼如下:

package mainimport ( "fmt" "net/http")func myWeb(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "這是一個(gè)開始")}func main() { http.HandleFunc("/", myWeb) fmt.Println("服務(wù)器即將開啟,訪問地址 http://localhost:8080") err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Println("服務(wù)器開啟錯(cuò)誤: ", err) }}保存文件,然后在命令行工具下輸入命令,運(yùn)行程序

$ go run main.go

這時(shí)候,你會(huì)看到用 fmt.Println打印出來的提示,在瀏覽器中訪問 http://localhost:8080你將訪問到一個(gè)頁面,顯示 "這是一個(gè)開始"

解讀

我們從程序運(yùn)行的順序去了解它的工作流程

首先,定義package main,然后導(dǎo)入包。

這里,導(dǎo)入了一個(gè)新的包 net/http,這個(gè)包是官方的,實(shí)現(xiàn)http客戶端和服務(wù)端的各種功能。Go語言開發(fā)Web服務(wù)的所有功能就是基于這個(gè)包(其他第三方的Go語言Web框架也都基于這個(gè)包,沒有例外)

先看main函數(shù)里發(fā)生了什么

第一句,匹配路由和處理函數(shù)

http.HandleFunc("/", myWeb)

調(diào)用http包的HandleFunc方法,匹配一個(gè)路由到一個(gè)處理函數(shù)myWeb。

這句代碼的意思是,當(dāng)通過訪問地址 http://localhost/ 時(shí),就等同于調(diào)用了 myWeb 函數(shù)。

第二句,用fmt在控制臺(tái)打印一句話,純屬提示。

第三句,開啟服務(wù)并且監(jiān)聽端口

err := http.ListenAndServe(":8080", nil)在這句,調(diào)用了http包中的ListenAndServe函數(shù),該函數(shù)有兩個(gè)參數(shù),第一個(gè)是指定監(jiān)聽的端口號(hào),第二個(gè)是指定處理請(qǐng)求的handler,通常這個(gè)參數(shù)填nil,表示使用默認(rèn)的ServeMux作為handler。

什么是nil?

nil就是其他語言里的null

什么是handler?什么是ServeMux?
ServeMux就是一個(gè)HTTP請(qǐng)求多路由復(fù)用器。它將每個(gè)傳入請(qǐng)求的URL與已注冊(cè)模式的列表進(jìn)行匹配,并調(diào)用與URL最匹配的模式的處理程序。
很熟悉吧?還記得前面的http.HandleFunc嗎?他就是給http包中默認(rèn)的ServeMux(DefaultServeMux)添加URL與處理函數(shù)匹配。
通常都是使用http包中的默認(rèn)ServeMux,所以在http.ListenAndServe函數(shù)的第二個(gè)參數(shù)提供nil就可以了
ListenAndServe函數(shù)會(huì)一直監(jiān)聽,除非強(qiáng)制退出或者出現(xiàn)錯(cuò)誤。

如果這句開啟監(jiān)聽出現(xiàn)錯(cuò)誤,函數(shù)會(huì)退出監(jiān)聽并會(huì)返回一個(gè)error類型的對(duì)象,因此用err變量接收返回對(duì)象。緊接著,判斷err是否為空,打印出錯(cuò)誤內(nèi)容,程序結(jié)束。


這里有兩個(gè)Go語言知識(shí)點(diǎn)

1.定義變量

Go語言是靜態(tài)語言,需要定義變量,定義變量用關(guān)鍵字var

var str string = "my string"//^ ^ ^//關(guān)鍵字 變量名 類型Go還提了一種簡單的變量定義方式:=自動(dòng)根據(jù)賦值的對(duì)象定義變量類型,用起來很像腳本語言:

str := "my string"

2.錯(cuò)誤處理

if err != nil{ //處理....}在Go語言中,這是很常見的錯(cuò)誤處理操作,另一種panic異常,官方建議不要使用或盡量少用,暫不做介紹,先從err開始。

Go語言中規(guī)定,如果函數(shù)可能出現(xiàn)錯(cuò)誤,應(yīng)該返回一個(gè)error對(duì)象,這個(gè)對(duì)象至少包含一個(gè)Error()方法錯(cuò)誤信息。

因此,在Go中,是看不到try/catch語句的,函數(shù)使用error傳遞錯(cuò)誤,用if語句判斷錯(cuò)誤對(duì)象并且處理錯(cuò)誤。


3. if 語句

與大多數(shù)語言使用方式一樣,唯一的區(qū)別是,表達(dá)式不需要()包起來。

另外,Go語言中的if可以嵌入一個(gè)表達(dá)式,用;號(hào)隔開,例如范例中的代碼可以改為:

if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Println("服務(wù)器開啟錯(cuò)誤: ", err)}err這個(gè)變量的生命周期只在if塊中有效。

請(qǐng)求處理 myWeb函數(shù)

main函數(shù)中,用http.HandleFunc將 myWeb與路由/匹配在一起。

HandleFunc函數(shù)定義了兩個(gè)參數(shù)w,r,參數(shù)類型分別是http.ResponseWriter*http.Requestw是響應(yīng)留寫入器,r是請(qǐng)求對(duì)象的指針。

響應(yīng)流寫入器 w: 用來寫入http響應(yīng)數(shù)據(jù)

請(qǐng)求對(duì)象 * r: 包含了http請(qǐng)求所有信息,注意,這里使用了指針,在定義參數(shù)時(shí)用*標(biāo)記類型,說明這個(gè)參數(shù)需要的是這個(gè)類型的對(duì)象的指針。

當(dāng)有請(qǐng)求路徑/,請(qǐng)求對(duì)象和響應(yīng)流寫入器被傳遞給myWeb函數(shù),并由myWeb函數(shù)負(fù)責(zé)處理這次請(qǐng)求。

Go語言中紅的指針: 在Go語言中 除了map、slice、chan 其他函數(shù)傳參都是值傳遞,所以,如果需要達(dá)到引用傳遞的效果,通過傳遞對(duì)象的指針實(shí)現(xiàn)。在Go語言中,取對(duì)象的指針用&,取值用*,例如:

mystring := "hi"//取指針mypointer := &mystring//取值mystring2 := *mypointerfmt.Println(mystring,mypointer,mystring2)把這些代碼放在main函數(shù)里,$ go run main.go運(yùn)行看看

myWeb函數(shù)體

fmt.Fprintf(w, "這是一個(gè)開始")再一次遇到老熟人fmt,這次使用他的Fprintf函數(shù)將字符串“這是一個(gè)開始”,寫入到w響應(yīng)流寫入器對(duì)象。w響應(yīng)流寫入器里寫入的內(nèi)容最后會(huì)被Response輸出到用戶瀏覽器的頁面上。

總結(jié)一下,從編碼到運(yùn)行,你和它都干了些什么:

  1. 定義一個(gè)函數(shù)myWeb,接收參數(shù) 響應(yīng)流寫入器和請(qǐng)求對(duì)象兩個(gè)參數(shù)
  2. 在main函數(shù)中,在默認(rèn)的ServeMux中將路由/與myWeb綁定
  3. 運(yùn)行默認(rèn)的ServeMux監(jiān)聽本地8080端口
  4. 訪問本地8080端口 / 路由
  5. http將請(qǐng)求對(duì)象和響應(yīng)寫入器都傳遞給myWeb處理
  6. myWeb向響應(yīng)流中寫入一句話,結(jié)束這次請(qǐng)求。
雖然代碼很少很少,但是這就是一個(gè)最基本的Go語言Web服務(wù)程序了。

Web互動(dòng)第一步,Go http 獲得請(qǐng)求參數(shù)

還是先從代碼開始

打開main.go文件,修改myWeb函數(shù),如下:

func myWeb(w http.ResponseWriter, r *http.Request) { r.ParseForm() //它還將請(qǐng)求主體解析為表單,獲得POST Form表單數(shù)據(jù),必須先調(diào)用這個(gè)函數(shù) for k, v := range r.URL.Query() { fmt.Println("key:", k, ", value:", v[0]) } for k, v := range r.PostForm { fmt.Println("key:", k, ", value:", v[0]) } fmt.Fprintln(w, "這是一個(gè)開始")}運(yùn)行程序

$ go run main.go

然后用任何工具(推薦Postman)提交一個(gè)POST請(qǐng)求,并且?guī)蟄RL參數(shù),或者在命令行中用cURL提交

curl --request POST / --url 'http://localhost:8080/?name=zeta' / --header 'cache-control: no-cache' / --header 'content-type: application/x-www-form-urlencoded' / --data description=hello頁面和終端命令行工具會(huì)答應(yīng)出以下內(nèi)容:

key: name , value: zetakey: description , value: hello

解讀

http請(qǐng)求的所有內(nèi)容,都保存在http.Request對(duì)象中,也就是myWeb獲得的參數(shù) r 。

首先,調(diào)用r.ParseForm(),作用是填充數(shù)據(jù)到 r.Formr.PostForm

接下來,分別循環(huán)獲取遍歷打印出 r.URL.Query() 函數(shù)返回的值 和 r.PostForm 值里的每一個(gè)參數(shù)。

r.URL.Query()r.PostForm 分別是URL參數(shù)對(duì)象和表單參數(shù)對(duì)象
,它們都是鍵值對(duì)值,鍵的類型是字符串string,值的類型是string數(shù)組。

在http協(xié)議中,無論URL和表單,相同名稱的參數(shù)會(huì)組成數(shù)組。
循環(huán)遍歷:for...range

Go語言的循環(huán)只有for關(guān)鍵字,以下是Go中4種for循環(huán)

//無限循環(huán),阻塞線程,用不停息,慎用!for{}//條件循環(huán),如果a<b,循環(huán),否則,退出循環(huán)for a < b{}//表達(dá)式循環(huán),設(shè)i為0,i小于10時(shí)循環(huán),每輪循環(huán)后i增加1for i:=0; i<10; i++{}//for...range 遍歷objs,objs必須是map、slice、chan類型for k, v := range objs{}前3種,循環(huán)你可以看作條件循環(huán)的變體(無限循環(huán)就是無條件的循環(huán))。

本例種用到的是 for...range 循環(huán),遍歷可遍歷對(duì)象,并且每輪循環(huán)都會(huì)將鍵和值分別賦值給變量 kv


我們頁面還是只是輸出一句“這是一個(gè)開始”。我們需要一個(gè)可以見人的頁面,這樣可以不行

你也許也想到了,是不是可以在輸出時(shí),硬編碼HTML字符串?當(dāng)然可以,但是Go http包提供了更好的方式,HTML模版。

接下來,我們就用HTML模版做一個(gè)真正的頁面出來

動(dòng)態(tài)響應(yīng)數(shù)據(jù)給訪客,Go http HTML模版+數(shù)據(jù)綁定

讀取HTML模版文件,用數(shù)據(jù)替換掉對(duì)應(yīng)的標(biāo)簽,生成完整的HTML字符串,響應(yīng)給瀏覽器,這是所有Web開發(fā)框架的常規(guī)操作。Go也是這么干的。

Go html包提供了這樣的功能:

"html/template"

從代碼開始

main函數(shù)不變,增加導(dǎo)入html/template包,然后修改myWeb函數(shù),如下:

import ( "fmt" "net/http" "text/template" //導(dǎo)入模版包)func myWeb(w http.ResponseWriter, r *http.Request) { t := template.New("index") t.Parse("<div id='templateTextDiv'>Hi,{{.name}},{{.someStr}}</div>") data := map[string]string{ "name": "zeta", "someStr": "這是一個(gè)開始", } t.Execute(w, data) // fmt.Fprintln(w, "這是一個(gè)開始")}在命令行中運(yùn)行 $ go run main.go ,訪問 http://localhost:8080

看,<div id='templateTextDiv'>Hi,{{.name}},{{.someStr}}</div> 中的{{.name}}{{.someStr}} 被替換成了 zeta這是一個(gè)開始。并且,不再使用fmt.Fprintln函數(shù)輸出數(shù)據(jù)到Response了

但是...這還是在代碼里硬編碼HTML字符串啊...

別著急,template包可以解析文件,繼續(xù)修改代碼:

  1. 根目錄下創(chuàng)建一個(gè)子目錄存放模版文件 templates, 然后進(jìn)入目錄創(chuàng)建一個(gè)文件 index.html,并寫入一些HTML代碼 (我不是個(gè)好前端)
<html><head></head><body> <div>Hello {{.name}}</div> <div>{{.someStr}}</div></body></html>
  1. 修改myWeb函數(shù)
func myWeb(w http.ResponseWriter, r *http.Request) { //t := template.New("index") //t.Parse("<div>Hi,{{.name}},{{.someStr}}<div>") //將上兩句注釋掉,用下面一句 t, _ := template.ParseFiles("./templates/index.html") data := map[string]string{ "name": "zeta", "someStr": "這是一個(gè)開始", } t.Execute(w, data) // fmt.Fprintln(w, "這是一個(gè)開始")}在運(yùn)行一下看看,頁面按照HTML文件的內(nèi)容輸出了,并且{{.name}}和{{.someStr}}也替換了,對(duì)吧?

解讀

可以看到,template包的核心功能就是將HTML字符串解析暫存起來,然后調(diào)用Execute的時(shí)候,用數(shù)據(jù)替換掉HTML字符串中的{{}}里面的內(nèi)容

在第一個(gè)方式中 t:=template.New("index") 初始化一個(gè)template對(duì)象變量,然后用調(diào)用t.Parse函數(shù)解析字符串模版。

然后,創(chuàng)建一個(gè)map對(duì)象,渲染的時(shí)候會(huì)用到。

最后,調(diào)用t.Execute函數(shù),不僅用數(shù)據(jù)渲染模版,還替代了fmt.Fprintln函數(shù)的工作,將輸出到Response數(shù)據(jù)流寫入器中。

第二個(gè)方式中,直接調(diào)用 template包的ParseFiles函數(shù),直接解析相對(duì)路徑下的index.html文件并創(chuàng)建對(duì)象變量。

知識(shí)點(diǎn)

本節(jié)出現(xiàn)了兩個(gè)新東西 map類型 和 賦值給“_

map類型

map類型: 字典類型(鍵值對(duì)),之前的獲取請(qǐng)求參數(shù)章節(jié)中出現(xiàn)的 url/values類型其實(shí)就是從map類型中擴(kuò)展出來的

map的初始化可以使用make

var data = make(map[string]string)data = map[string]string{}
make是內(nèi)置函數(shù),只能用來初始化 map、slice 和 chan,并且make函數(shù)和另一個(gè)內(nèi)置函數(shù)new不同點(diǎn)在于,它返回的并不是指針,而只是一個(gè)類型。
map賦值于其他語言的字典對(duì)象相同,取值有兩種方式,請(qǐng)看下面的代碼:

data["name"]="zeta" //賦值name := data["name"] //方式1.普通取值name,ok := data["name"] //方式2.如果不存在name鍵,ok為false
代碼中的變量ok,可以用來判斷這一項(xiàng)是否設(shè)置過,取值時(shí)如果項(xiàng)不存在,是不會(huì)異常的,取出來的值為該類型的零值,比如 int類型的值,不存在的項(xiàng)就為0;string類型的值不存在就為空字符串,所以通過值是否為0值是不能判斷該項(xiàng)是否設(shè)置過的。
ok,會(huì)獲得true 或者 false,判斷該項(xiàng)是否設(shè)置過,true為存在,false為不存在于map中。
Go中的map還有幾個(gè)特點(diǎn)需要了解:

  1. map的項(xiàng)的順序是不固定的,每次遍歷排列的順序都是不同的,所以不能用順序判斷內(nèi)容
  2. map可以用for...range 遍歷
  3. map在函數(shù)參數(shù)中是引用傳遞(Go語言中,只有map、slice、chan是引用傳遞,其他都是值傳遞)

賦值給 “_”

Go有一個(gè)特點(diǎn),變量定義后如果沒使用,會(huì)報(bào)錯(cuò),無法編譯。一般情況下沒什么問題,但是極少情況下,我們調(diào)用函數(shù),但是并不需要使用返回值,但是不使用,又無法編譯,怎么辦?

"_" 就是用來解決這個(gè)問題的,_用來丟棄函數(shù)的返回值。比如本例中,template.ParseFiles("./templates/index.html") 除了返回模版對(duì)象外,還會(huì)返回一個(gè)error對(duì)象,但是這樣簡單的例子,出錯(cuò)的可能性極小,所以我不想處理error了,將error返回值用“_”丟棄掉。

注意注意注意:在實(shí)際項(xiàng)目中,請(qǐng)不要丟棄error,任何意外都是可能出現(xiàn)的,丟棄error會(huì)導(dǎo)致當(dāng)出現(xiàn)罕見的意外情況時(shí),非常難于Debug。所有的error都應(yīng)該要處理,至少寫入到日志或打印到控制臺(tái)。(切記,不要丟棄 error ,很多Gopher們?cè)谶@個(gè)問題上有大把的血淚史)
OK,到目前為止,用Go語言搭建一個(gè)簡單的網(wǎng)頁的核心部分就完成了。

等等 .js、.css、圖片怎么辦?

對(duì)。例子里的模版全是HTML代碼,一個(gè)漂亮的網(wǎng)頁還必須用到圖片、js腳本和css樣式文件,可是...和PHP不同,請(qǐng)求路徑是通過HandleFunc匹配到處理函數(shù)的,難道要把js、css和圖片都通過函數(shù)輸出后,再用HandleFunc和URL路徑匹配?

處理好js、css和圖片,才能做漂亮的網(wǎng)頁,Go http靜態(tài)文件的處理辦法

以在index.html文件里引用一個(gè)index.js文件為例。

從代碼開始

func main() { http.HandleFunc("/", myWeb) //指定相對(duì)路徑./static 為文件服務(wù)路徑 staticHandle := http.FileServer(http.Dir("./static")) //將/js/路徑下的請(qǐng)求匹配到 ./static/js/下 http.Handle("/js/", staticHandle) fmt.Println("服務(wù)器即將開啟,訪問地址 http://localhost:8080") err := http.ListenAndServe(":8080", nil) if err != nil { fmt.Println("服務(wù)器開啟錯(cuò)誤: ", err) }}在項(xiàng)目的根目錄下創(chuàng)建static目錄,進(jìn)入static目錄,創(chuàng)建js目錄,然后在js目錄里創(chuàng)建一個(gè)index.js文件。

alert("Javascript running...");打開之前的index.html文件,在</body>后面加上 <script src="/js/index.js"></script>

運(yùn)行 $ go run main.go,訪問 http://localhost:8080,頁面會(huì)彈出提示框。

解讀

頁面在瀏覽器中運(yùn)行時(shí),當(dāng)運(yùn)行到<script src="/js/index.js"></script>瀏覽器會(huì)請(qǐng)求 /js/index.js這個(gè)路徑

程序檢查到第一層路由匹配/js/,于是用文件服務(wù)處理這次請(qǐng)求,匹配到程序運(yùn)行的路徑下相對(duì)路徑./static/js。

匹配的設(shè)置是 main.go文件中這兩句

//指定相對(duì)路徑./static 為文件服務(wù)路徑 staticHandle := http.FileServer(http.Dir("./static")) //將/js/路徑下的請(qǐng)求匹配到 ./static/js/下 http.Handle("/js/", staticHandle)也可以寫成一句,更容易理解

//瀏覽器訪問/js/ 將會(huì)以靜態(tài)文件形式訪問目錄 ./static/jshttp.Handle("/js/", http.FileServer(http.Dir("./static")))很簡單...但是,可能還是不滿足需求,因?yàn)? 如果

http.Handle("/js/", http.FileServer(http.Dir("./static"))) 對(duì)應(yīng)到 ./static/js

http.Handle("/css/", http.FileServer(http.Dir("./static"))) 對(duì)應(yīng)到 ./static/css

http.Handle("/img/", http.FileServer(http.Dir("./static"))) 對(duì)應(yīng)到 ./static/img

http.Handle("/upload/", http.FileServer(http.Dir("./static"))) 對(duì)應(yīng)到 ./static/upload

這樣所有請(qǐng)求的路徑都必須匹配一個(gè)static目錄下的子目錄。

如果,我就想訪問static目錄下的文件,或者,js、css、img、upload目錄就在項(xiàng)目根目錄下怎么辦?

http包下,還提供了一個(gè)函數(shù) http.StripPrefix 剝開前綴,如下:

//http.Handle("/js/", http.FileServer(http.Dir("./static"))) //加上http.StripPrefix 改為 : http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./static"))))這樣,瀏覽器中訪問/js/時(shí),直接對(duì)應(yīng)到./static目錄下,不需要再加一個(gè)/js/子目錄。

所以,如果需要再根目錄添加多個(gè)靜態(tài)目錄,并且和URL的路徑匹配,可以這樣:

http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./js")))) 對(duì)應(yīng)到 ./js

http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./css")))) 對(duì)應(yīng)到 ./css

http.Handle("/img/", http.StripPrefix("/img/", http.FileServer(http.Dir("./img")))) 對(duì)應(yīng)到 ./img

http.Handle("/upload/", http.StripPrefix("/upload/", http.FileServer(http.Dir("./upload")))) 對(duì)應(yīng)到 ./upload

到這里,一個(gè)從流程上完整的Web服務(wù)程序就介紹完了。

整理一下,一個(gè)Go語言的Web程序基本的流程:

  1. 定義請(qǐng)求處理函數(shù)
  2. 用http包的HandleFunc匹配處理函數(shù)和路由
  3. ListenAndServe開啟監(jiān)聽
當(dāng)有http請(qǐng)求時(shí):

  1. http請(qǐng)求到監(jiān)聽的的端口
  2. 根據(jù)路由將請(qǐng)求對(duì)象和響應(yīng)寫入器傳遞給匹配的處理函數(shù)
  3. 處理函數(shù)經(jīng)過一番操作后,將數(shù)據(jù)寫入到響應(yīng)寫入器
  4. 響應(yīng)給請(qǐng)求的瀏覽器

最后編譯程序

之前調(diào)試都使用的是 go run 命令運(yùn)行程序。

您會(huì)發(fā)現(xiàn),每次運(yùn)行go run都會(huì)重新編譯源碼,如何將程序運(yùn)行在沒有Go環(huán)境的計(jì)算機(jī)上?

使用 go build 命令,它會(huì)編譯源碼,生成可執(zhí)行的二進(jìn)制文件。

最簡單的 go build 命令什么參數(shù)都不用加,它會(huì)自動(dòng)查找目錄下的main包下的main()函數(shù),然后依次查找依賴包編譯成一個(gè)可執(zhí)行文件。

其他依賴文件的相對(duì)路徑需要和編譯成功后的可執(zhí)行文件一致,例如范例中的templates文件夾和static文件夾。

默認(rèn)情況下,go build會(huì)編譯為和開發(fā)操作系統(tǒng)對(duì)應(yīng)的可執(zhí)行文件,如果要編譯其他操作系統(tǒng)的可執(zhí)行文件,需要用到交叉編譯。

例如將Linux和MacOSX系統(tǒng)編譯到windows

GOOS=windows GOARCH=amd64 go build

在Windows上需要使用SET命令, 例如在Windows上編譯到Linux系統(tǒng)

SET GOOS=linuxSET GOARCH=amd64go build main.go

結(jié)語,學(xué)到了什么?還要學(xué)什么?

學(xué)到了什么?

  1. 快速簡單搭建Go開發(fā)環(huán)境
  2. 導(dǎo)入包、申明包
  3. func 定義函數(shù)
  4. 變量的申明方法
  5. Go語言的異常處理
  6. for循環(huán)
  7. map類型
  8. 用http包,編寫一個(gè)網(wǎng)站程序
本系列內(nèi)容很少,很簡潔,希望您能對(duì)Go多一點(diǎn)點(diǎn)了解,對(duì)Go多增加一點(diǎn)點(diǎn)興趣。

沒有涉及的其他知識(shí)

還有很多內(nèi)容成為一個(gè)合格的Gopher必須要了解的知識(shí)

  1. struct 結(jié)構(gòu)體
  2. 給struct定義方法
  3. interface 接口定義和實(shí)現(xiàn)
  4. chan類型
  5. slice類型
  6. goroutine
  7. panic處理
以后的文章中會(huì)涉及更多關(guān)于Go語言編程的內(nèi)容

歡迎關(guān)注曉代碼公眾號(hào),和大家一起學(xué)習(xí)吧

曉代碼


關(guān)鍵詞:依賴,語言

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點(diǎn)擊下載Chrome瀏覽器
關(guān)閉