語言學(xué)習(xí)作者資深碼農(nóng)一枚沒什么名氣也學(xué)歷教程中肯定會有_第1頁
語言學(xué)習(xí)作者資深碼農(nóng)一枚沒什么名氣也學(xué)歷教程中肯定會有_第2頁
語言學(xué)習(xí)作者資深碼農(nóng)一枚沒什么名氣也學(xué)歷教程中肯定會有_第3頁
語言學(xué)習(xí)作者資深碼農(nóng)一枚沒什么名氣也學(xué)歷教程中肯定會有_第4頁
語言學(xué)習(xí)作者資深碼農(nóng)一枚沒什么名氣也學(xué)歷教程中肯定會有_第5頁
已閱讀5頁,還剩179頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

前 “反射”之后緊接著就是如何實現(xiàn)一個ORM,實用性強,注重實際應(yīng)用。再比如網(wǎng)絡(luò)編程一節(jié),會講設(shè)計一個TCP和UDP程序的不同,TCP程序需自定義通信格式,UDP需要雙方約定UDP包的大小。本 的第最后一章向大家介紹一個GoMvc框架。:第1前 第一章GO語言的安 安裝 安裝go語言開發(fā)工 安裝 第二章GO語言基 基本類 定義變 數(shù) 切片 常 控制 if 2.52 for循 第三章函 函數(shù)定 多值返 變參函 函數(shù)類 錯誤處 第四章面向?qū)ο缶? 繼 第五章多線 多線 進程同 第六章日期與定時 日期的獲取與計 定時 路 文件讀 遍 下的文 第2gob序列 第8章JSON與XML解 XML序列化與解 JSON序列化與反序列 第9章MySQL數(shù)據(jù)庫操 安裝MySQL驅(qū) MySQL數(shù)據(jù)庫操 事 標(biāo)準(zhǔn)驅(qū)動的不足與改 第10章反 反射基 反射調(diào)用函 反射取Struct的Tag信 第11章實現(xiàn)一個自己的 實現(xiàn)自己的 Insert函數(shù)的實現(xiàn)及所有源 第12章TCP與UDP網(wǎng)絡(luò)編 第十三章WEB編 第一個WEB程 文件上 模板展 第十四章GoMvcWeb框 MVC簡 GoMvc簡 結(jié) 配置文 路 第3第一章GO語言的安裝goGo語言是由 語言語法靈活、簡潔、清晰、高效。它對的并發(fā)特性可以方便地用于多核處理器和網(wǎng)絡(luò)開內(nèi)存自動回收功能,并且還支持運行時反射。Go是一個高效、靜態(tài)類型,但是又具有Golang官網(wǎng) ,在國內(nèi)可能打不開,可以使用goagent 以windows為例,首先從go語言官網(wǎng)http 新的go安裝包。將其解壓到本地硬盤。 的安裝只要設(shè)置相應(yīng)的環(huán)境變量就可以了,相關(guān)環(huán)境變量如下 第4GOBIN表示編譯器和器的安裝位置,默認(rèn)是$GOROOT/bin,如果你使用的是Go1.0.3及以后的版本,一般情況下你可以將它的值設(shè)置為空,Go將會使用前面提到的默GOARCH386,amd64arm我的機器是windows64位,所以設(shè)置為amd64。如果你的機器是32位的設(shè)置為386我用的是windows,所以設(shè)置為windows。GOMAXPROCS:用于設(shè)置應(yīng)用程序可使用的處理器個數(shù)與核數(shù)第5GOMAXPROCS環(huán)境變量,程序只使用一個線程。為了利用全部CPU內(nèi)核,則必須制定它的值。我的CPU是i7,四核,所以該變量本人設(shè)置為4GOPATHGo項目源代碼和二進制文件的。GOPATH允許多個,當(dāng)有多個GOPATHWindows是分號,Linux系統(tǒng)是冒號,當(dāng)有多個GOPATHgoget的內(nèi)容放在第一個下。以上 src存放源代碼(比如:.go.ch.s等pkg編譯后生成的文件(bin編譯后生成的可執(zhí)行文件(為了方便,可以把此 加入到$PATH變量中) 這里我把k:\go做我工 。如下圖所示warning:warning:GOPATHsettoGOROOT(E:\go)hasnoeffectOT.Formoredetailssee:gohelpgopath填%GOBIN%,或直接寫路徑如e:\go\bin。開始->運行->輸入cmd,打開命令行窗口,輸入go回車,出現(xiàn)下圖信息,說明安裝成功第6至于其它系統(tǒng)的安裝,大同小異,如在安裝過程中遇到問題可 一下安裝go語言開發(fā)工 liJIDEALiteIDE是一款專為Go語言開發(fā)而設(shè)計的跨平臺輕量級集成開發(fā)環(huán)境(IDE),基于Qt開發(fā),支Windows、LinuxMacOSX平臺。LiteIDE的第一個版本發(fā)20111月初,是最早的面向Go語言的IDE之一。 版本。解壓到本地硬盤第7我是放在了E:\Program 下。右擊liteide.exe,在彈出的右鍵菜單中選擇發(fā)送到->桌面快捷方式。在桌面上他建快捷方式旁邊的黑色按扭,編lite的環(huán)境配置。##nativecompilerwindowsamd64第8別忘了保存編輯后的文件文件->新建,打開新 框,名稱輸入test_go。點擊OK創(chuàng)建一個命令行項目在菜單中選擇Build->BuildAndRun,編譯并運行程序第9 liJ liJIDEA被認(rèn)為是當(dāng)前Java開發(fā)效率最快的IDE工具。它整合了開發(fā)過程中實用簡單而又功能強大。與其他的一些繁冗而復(fù)雜的IDE工具有鮮明的對比。In liJIDEA下有g(shù)olang插件,技持go的開發(fā)。打開 liJIDEA,點選Configure,如下圖所示再選Plugins,如下圖所示10在 框中,點Browserepositores...,如下圖所11.在新窗口中找的插件,右擊->選擇”DownloadandInstall”12關(guān)閉當(dāng)前窗口,返回 框,找到golang插件,點擊選擇,再點右下角的按鈕重啟 liJIDEA,如下圖所示13重啟后,點CreateNewProjiect,打開新建項目的 ,要左則選擇GoModule,在右邊14gogogoProjectSDK右邊的”New...”golang的安裝位E:\go下Gocode是的Go語言的一個代碼自動補全的工具,對于windows程序員應(yīng)該很熟悉VS的代碼提示功能,很強大。在不安裝gocode的情況下,LiteIDE是沒有代碼提示的,所以最好能裝gocode。經(jīng)測InliJIDEA不需要安gocode就可以代碼InliJIDEA的代碼提示功能要比LiteIDE強大。Gocode 上的一個開源項目,地址是 /nsf/gocode。開->運行->輸入cmd打開命令行窗口。輸入如下命令來安裝gocode如果提示下面的信息,說明沒有安裝git。 版本15并安裝go:missinggo:missingGitcommand./nsf/gocode:exec:"git":executablefilenotfoundinRunGitfromtheWindowsCommandPrompt,這樣就不需要手動在Path里面設(shè)置git的路徑,可以在命令行運行g(shù)it命令。安裝成功后,關(guān)閉原來打開令窗口,再重新打開一個命令窗口,重新運行上面的gocode令。命令執(zhí)行成功后gocode將安裝GOPATH的位置,我設(shè)置的是K:\go,gocode將會安裝在這個。如下圖所示:1617第二章GO語言基Go程import()func{o第一行,package定義了程main。第二import引入了fmt包。funcmain定了main函數(shù),func是函main函數(shù)調(diào)fmt包的Println函數(shù),輸出了oWorld!”在所有初始化完成后,程序從main包中的main函數(shù)開始執(zhí)行Go中的所有字符串,都UTF-8編碼。所有的Go語言源文件也都是采UTF-8編碼。在Go語言中,語句末尾的分號可以省略不寫?;绢?對整數(shù)進行了更明確的規(guī)劃,清晰明了。Go里的基本類型如下表類長度(字節(jié)說11uint84 Unicode432bit64bit11-128 127; 2- 32767; 4-21億 21億 428復(fù)數(shù)類型,即32位實數(shù)+32復(fù)數(shù)類型,即64位實數(shù)+643264數(shù)組,值類型,如:[2]結(jié)構(gòu)體,值類類型如 類類18接口類函數(shù)類定義變Go語言里面定義變量有多種方使用var關(guān)鍵字是Go最基本的定義變量方式,最常見的語法如下varn /*定義變量variint=3 strvari1,i2,i3int=1,2,3/*定義多個變量并賦值var ”;/*Go會自動檢測變量的類型packagemain funcmain(){varbvarnpackagemain funcmain(){varbvarn /*定義變量variint=3/*定義變量i并賦值3*/var( strstring)vari1,i2,i3int123/*定義多個變量并賦值varstrName /*Go會自動檢測變量的類型strSex"男/*:=定義變量,并給變量賦值,可以省略var關(guān)鍵fmt.Println("n=",fmt.Println("b",fmt.Println("i=",i)fmt.Println("aa=",aa)fmt.Println("strName=",strName)fmt.Println("strSex=",strSex)}編譯并運行程序,你會發(fā)現(xiàn)b=false,n=0;對于未賦值的變量,Go會自動初始化,數(shù)值 類型初始值為false,字符串初始值為空。19數(shù)array是固定長度的數(shù)組,這個和C語言中的數(shù)組是一樣的,使用前必須確定數(shù)組長度。但是和C中的數(shù)組相比,又是有一些不同的:o中的數(shù)組是值類型,換句話說,如果你將一個數(shù)組賦值給另外一個數(shù)組,那么,實際上就是將整個數(shù)組拷貝一份如果Go中的數(shù)組作為函數(shù)的參數(shù),那么實際傳遞的參數(shù)是一份數(shù)組的拷貝,而不是數(shù)組的指針。這個和C要區(qū)分開。因此,在Go中如果將數(shù)組作為函數(shù)的參數(shù)傳遞的話,那效array的長度也是Type的一部分,這樣就說明[10]int和[20]intarray的結(jié)構(gòu)用圖示表示是這樣len表示數(shù)組的長度,后面的int vararr_1[2]int/*一個2個元素的數(shù)組arr_2,并同時賦初值,{}里為空,說明沒有賦初值,arr_2:= arr3:=[2]int{1,2}arr3_1:=[2]int{0:1,1:2}arr3_2:=/*不指定數(shù)組長度,自動計算長度,[...],一個2個(自動計算而來)元素的數(shù)組,名arr4,并同時賦初值,結(jié)果為[1,2]*/arr4:= 一個4個(動計算而來)元素的名字為shuzu5時賦初值,結(jié)果為完整代碼如下20 一個2個元素的數(shù)組,名字為arr_1,因為是int型數(shù)組,所以初值為0,即[0,0]vararr_1[2]intimport()funcmain()為為}*不指定數(shù)組長度,自動計算長度,[...], 為arr4,并同時賦初值,結(jié)果為[1,2]*/arr4:=[...]int{1, 一個4個(自動計算而來)元素的數(shù)組,名字為shuzu5,并同時賦初值arr3:=[2]int{1,arr3_1:=[2]int{0:1,1:2}arr3_2:=[2]int{1:2,0: 特定的空間,或者其它數(shù)組的空間。在Go語言中Slices比數(shù)組使用的更為普遍,因為它更有彈性, []T是一個T類型的片,切片不需要指定長度,指定長度就成了數(shù)組。切片可以被重新分片。創(chuàng)建一個指向同一數(shù)組的指針。s[lo:hi]lohi-1s[lo:lo]是空的。21的數(shù)組p的數(shù)組p第一個和第二個元素,所以數(shù)組p的值被改//切片packagemainimport"fmt"funcmain(){s1:=p[1:3] fmt.Println(reflect.TypeOf(s1))//s1是切片類型[]intChangeArrayValue(p)//ChangeArrayValue函數(shù)將第一個值改為100 //數(shù)組p的值并沒有改變,因為數(shù)組是值類型 }}{arr[0]=}{slice[0]=}。key必須是支持比較運算符(==、!=)的類型。如number、string、pointer、array、Map用make來分配內(nèi)存空間,mak(map[TK]TV),TK是key的類型,TVimport()funcmain()mp:=make(map[string]string)//key是字符串類型,值也是字符串類mp["a"]=mp["b"]=mp["pi"]= mp["sh"]="22ififok}elsefmt.Println("keysh''不存在}ifok{}elsefmt.Println("key'bj'不存在}}import()funcmain()arr:=[3]int{1,2,varmp=map[int]string{1:"a",2:"b",3:"c"}fork,v:=rangemp{}for_,v:=range{}}常常量必須是編譯期能確定的,常量的定義使用const,常量的類型可以是char以被編譯器求值。例如,1<<3是常量表達式,math.Sin(math.Pi/4)不是,因為math.Sin的函數(shù)調(diào)用發(fā)生在運行態(tài)。23constconstconstUserName,SexconstUserName,Sex=funcmain() }值。按行遞增,可以省略后續(xù)行的iota關(guān)鍵字。constconst)/*Sunday=0Monday=1Tuesday=可以在同一行使用多個iota,它們各自增長funcfunc{constU,V=iota,iotaW,XY,)/*U=0V=0W=1X=1Y=2Z=fmt.Println("U=",U,"V=",V,"W=",W,"X=",X,"Y=",Y,"Z=",}如果某行不想遞增,可單獨提供初始值。不過想要恢復(fù)遞增,必須再次使 func{conststr 24 //沒有賦值,跟上一行一樣,要想恢復(fù)自增,需再次賦值iota =iota)/*A1=0A2=1 o oA3=4A4=}}ifa:=a:=ifa==2}在if和條件之間可以包括一個初始化表達式,上面的代碼碼可以寫成ififa:=2;a==2}在if條件里初始化的變量,作用域是這個if,語句塊,如上面代碼中的變量a,只能在ifa:=2;a<2}elsefmt.Println("a="ifa:=2;a<2}elsefmt.Println("a=",}下面的代碼是錯誤的,因為if和條件之間只能有一個初始化表達25ififa:=2;b:=100;a==2}2.52Goswitch非常靈活,表達式不必是常量或整數(shù),執(zhí)行的過程從上至下,直到找到匹配項;而如果switch沒有表達式,它會匹配true。Go里面switch默認(rèn)相當(dāng)于每個case最后帶有break,匹配成功后不會自 他case,而是跳出整個switch,但是可以使用fallthrough強制執(zhí)行后面的case代碼。funcfunc{i:=switch{casefmt.Println("iisequalto1")case2:fmt.Println("iisequalto2")case3456//case可以有多個值fmt.Println("iisequalto3,4,5or}}不指定switch條件表達式,或直接為true時,可用于替代if...else...if...elsefuncfunc{result:=ifresult<0fmt.Println("小于零}elseifresult>}elsefmt.Println("等于零上面的代碼可改寫為switch看起來更加清晰明了26 {result {caseresult<caseresult>0:fmt.Println("等于零forGo只有一個關(guān)鍵字用于引入循環(huán)。但它提供了除do-while外C語言當(dāng)中所有可用的循Go的for循環(huán)有如下三種形式forforinit;condition;post←Cforfor ←死循初始化表達式計算。在for初始for中,i,jfor句中有效。str:=str:=funcmain()forfori,j:=0,len(str);i<j;{}}func{i:=forififunc{i:=forifi>10}}}27嵌套循環(huán)時,可以在break后面指 ,用來指定要終止哪兒個循環(huán)funcfunc{fori:=0;i<5;i++{fork:=0;k<5;k++{ifi>0break}}}} 用于終止本次循環(huán)體的執(zhí)行繼續(xù)執(zhí)行下一個循環(huán)。下面是打印非空格符strstr:= ofori,j:=0,len(str);i<j;i++ifstring(str[i])==""}}與break相同,對于嵌套循環(huán),可以 ,來指定要繼續(xù)哪一層循環(huán)funcfunc{fori:=0;i<5;i++fork:=0;k<100;{ifk>0continue}}}}28第三章函數(shù)函數(shù)定Go是面向過程的編程語言,函數(shù)是Go程序的基本部件funcfuncAdd(a,bint){returna+}func是定義函數(shù)的關(guān)鍵字,Add是函數(shù)名;int是返回值??梢噪S意安排函數(shù)定義的順序,Go編譯時會掃描所有的文件。packagepackageimport)func{}func{}func{}多值返GoGo語言中是經(jīng)常被用到的,比如,一個函數(shù)同時返回結(jié)果和異常。例如打開文件的函數(shù)funcOpen(namestring)(file*File,errerror)。package下面我們看一個例子,divide函數(shù)是計算a/b的結(jié)果,并返回商和余package29importimport)funcdivide(a,bint)(int,{quotient:=a/bremainder:=a%breturnquotient,}funcmain()q,r:=divide(5,3)fmt.Println(q,",",r)}return上面的divide函數(shù),可以使用命名的返回值,如下funcfuncdivide(a,bint)(quotient,remainder{quotient=a/bremainder=a%b}變參函Goslice,且必須是最后一個參數(shù)。將sliceimport(){s:=for_,number:=range{s+=}return}30funcfuncmain()total:=sum(1,2,3,4)sliceint{123456789//等價于sum(1,2,3,4,5,6,7,8,9)}defer是Go語言所特有的,defer的作用是延遲執(zhí)行,在函數(shù)返回前,按照后進先出的原則defer的函數(shù)。這樣可以保證,函數(shù)在返回前被調(diào)用,通常且來進import(){f,err:=os.Open(strFileName)iferr!=nil{return"",}deferf.Close//在函數(shù)返回前關(guān)閉文件buf:=make([]byte,1024)varstrContentstring=""for{ifn==0{}strContent+=}returnstrContent,}funcmain()str,err:=31ififerr!=nil}}函數(shù)類函數(shù)也是一種類型,,擁有相同參數(shù),相同返回值的函數(shù),是同一種類型。用type來定義函數(shù)類型。下面的Display函數(shù)輸5的數(shù)值。import()typeMyFuncTypefunc(int)boolfuncIsBigThan5(nint)bool{returnn>}{for_,v:=rangearr{iff(v){}}}funcmain()arr:=[]int{1,2,3,4,5,6,7,8,}在上面的例子中,typeMyFuncTypefunc(int)bool定義了一個函數(shù)類型,將其命名為MyFuncType,接受一intbool類型的結(jié)果。IsBigThan5MyFuncType類型的函數(shù)。函數(shù)類型,跟C里的函數(shù)指針有點像。錯誤處Go語言中沒try...catch...finally這種結(jié)構(gòu)化異常處理,而是panicthrow拋出異常。使recover函數(shù)來捕獲異常。Recoverdefer函數(shù)中使用才能捕獲異常州,此時函數(shù)32import()func{defer{iferr:=recover();err!={}divide(5,0) fmt.Println("endoftest") }funcdivide(a,bint){returna/}func{33Go是面向過程的語言,GoGo支持面向?qū)ο竦木幊?,Gostruct就像其它語中的類;Go里沒有繼承,但可以用組合來實現(xiàn)。結(jié)構(gòu)體是一種自定義類型,是不同數(shù)據(jù)的集合體struct是值類型。通常用來定義一個抽像的數(shù)據(jù)對像,比如學(xué)生,可以有、、班級等數(shù)據(jù)構(gòu)成,struct值類型。結(jié)構(gòu)typetypeStudentstruct成員名字1類型1成員名字2類型2成員名字3類型}可以用New來創(chuàng)建結(jié)構(gòu)體,然后對各字段進行賦{Namestring classstring}funcmain()s1.Name= s1.Age=12s1.class"21班"}除了上面這種方式,還可以使用以兩種式定義,初始化結(jié)構(gòu)按照順序提供初始化 ”,12,”2班通過field:value 班Go語言沒有class,不支持面向?qū)ο?。但支持面向struct結(jié)構(gòu)體的成員函數(shù),使用方法34面向?qū)ο缶幊谭绞较嗨?。定義格式如func)函數(shù)名(參數(shù)列表返回值類型列表s:=Student{Name:{s:=Student{Name:{Namestring classstring}func(thisStudent)getName(){return}//結(jié)構(gòu)體可以傳指針類{return}funcmain()}繼Goclass,但可以把structclass來看Go不能class那樣繼承可以通 字段來實現(xiàn)繼承packagepackagemain {Namestring classstring}func(this*StudentDisplay}//定義一個大學(xué)生類,繼承StudenttypeCollegeStudentstruct{}35s1s1:=CollegeStudent{Student:Student{Name:Profession:"物理Profession:"物理) }CollegeStudentStudent的所有字段和方法。CollegeStudent也可以重寫繼承的方funcfunc(this*CollegeStudent)}上 ,大寫開頭的相當(dāng)于public,小寫開頭的是private,包外是不可

"Age23class:"2004(2)班funcmain()如果包a中的一個結(jié)構(gòu),去繼承b包中結(jié)構(gòu)體,只有大寫"Age23class:"2004(2)班funcmain()typeStudentstruct{ classstring/*小寫開頭的包外不可見,包外的結(jié)構(gòu)體也無法繼承該字段}下面我們在main包中繼承import(){}funcmain()s:=MyStudent{}s.Student.class="aaaa"}編譯時將報錯,s.Student.classundefined(cannotrefertounexportedfieldormethodclass)。 36包名必須跟所 名一至import()typeFruitstruct}func(this*Fruit){}func(this*Fruit)GetName()return}typeApple{}func(this*Apple)GetName()return}func{fruit:=apple:=Apple{}}上面代碼運行結(jié)果為37在上面的例子中,Apple繼承了Friut,并且重載了GetName函數(shù),我們期望的結(jié)果重寫Display函數(shù),這樣做是絕對沒有問題。但通常Display里是一些通用的業(yè)務(wù)邏輯,我不想在每個類中都去重寫這個函數(shù),這樣不利于代碼的。要想實packagepackageimport)typeFruitNamefunc()typeFruit{GetFruitName}func(this*Fruit){}func(this*Fruit)GetName()return}funcNewFriut(){f:=new(Fruit)f.GetFruitName=f.GetNamereturnf}typeApple{}func(this*Apple)GetName()return}funcNewApple(){a:=new(Apple)a.GetFruitName=a.GetNamereturna}funcmain()fruit:=38appleapple:=NewApple()}上面程序的運行結(jié)果上面例子中先用typeFruitNamefuncstring定義了一個FruitName函數(shù)類型,然后在Friut結(jié)構(gòu)體中定義了一個FruitName函數(shù)類型的成員GetFruitName。在NewAppleNewFriut中對GetFruitName進行了賦值,在DisplayName函數(shù)中調(diào)用了GetFruitName。接口是一系列操作的集合,是一種約定。我們可以把它看作與其它對象通訊的協(xié)議。任接口類型只要擁有某接口的全部方法,就表示它實現(xiàn)了該接口,o中無需顯式在該類上添加接 {Namestring classstring}{GetName()stringGetAge()int}{return}func(this*Student)GetAge(){return}funcmain()vars1IStudent "23"2004(2)班}Interface{}沒有定義任何方法,稱為空接口。任何類型默認(rèn)都實現(xiàn) interface{},相39于C語言中的void*指針40第五章多線程線程是CPU調(diào)度的最小單位,只有不同的線程才能同時在多核CPU上同時運行。但線程太占資源,線程調(diào)度Go中的goroutine是一個輕量級的線程,執(zhí)行時只需要4-5K的內(nèi)存,比線程更易用,更高效,更輕便,調(diào)度開銷比線程小,可同時運行上千萬個并發(fā)。Go語言中來啟一個goroutine非常簡單,Go函數(shù)名(),就開啟了個線程。默認(rèn)情況下,調(diào)度器僅使用單線程,要想發(fā)揮多核處理器的并行處理能力,必須調(diào)用runtime.GOMAXPROCS(n)來設(shè)置可并發(fā)的線程數(shù),也可以通過設(shè)置環(huán)境變量GOMAXPROCS達到相同的目的(在第一章,安裝Go中有介紹。Runtime包中提供了幾個與goroutine有關(guān)的函數(shù)。Gosched()讓當(dāng)前正在執(zhí)行的goroutine放棄CPU執(zhí)行權(quán)限。調(diào)度器安排其它正在等待的線程運行。如下面的程序,開啟兩個 o,一個輸出world。go go }}fori:=0;i<10;{)}}funcmain()ofori:=0;i<10;func o()import()gogotime.Sleep(5*}上面程序的運結(jié)果是輸出幾行

oWorld!,首先啟動了一個

o線程,接著起動SayWorld線程,在

o線程中輸

41 o,SayWorld在多核CPU上是同時運行的,我的環(huán)境變量設(shè)置為了8,輸出結(jié)果也 oWorld!,沒有出 NumCPU()返回CPU核數(shù),NumGoroutine()返回當(dāng)前進程的Goroutine線程數(shù)。即便我們沒有開啟新goroutine,NumGoroutine()也是2,這是因為除了主線程main,go還會啟動一個GCHeap用來對內(nèi)存進行管理及回收。importimport)func{fmt.Println(runtime.NumCPU())}CPUI7,四核,NumCPU(),返回的結(jié)果8,因in的超線程技術(shù),可以在一個實體處理器中,運行兩個邏輯線程(具體可以去一下超線程)。雖然我是四核,但是有8個邏輯內(nèi)核。runtime.Goexit()函數(shù)用于終止當(dāng)前goroutine,但defer函數(shù)將會被繼續(xù)調(diào)用import()func{defer{fmt.Println("infori:=0;i<10;{fmt.Println(i)ifi>5{}}}func{gotest()varstrstringGOMAXPROCS(nint) 用來設(shè)置可同時運行的線程數(shù),并返回當(dāng)前設(shè)置的值,如 將不會改變當(dāng)前的設(shè)置。通常這樣使用runtime.GOMAXPROCS(runtime.NumCPU()42importimport)func}運行程序,輸出結(jié)果為4,在第一章中提到我的GOMAXPROCS環(huán)境變量設(shè)置值為4列。你可以從一個goroutine中向channel發(fā)送數(shù)據(jù),在另一個goroutine中取出這個值。生費goroutine從channel中取出數(shù)據(jù)進行處理。import"fmt"funcproducer(cchan{deferclose(c)//關(guān)閉channelfori0i10;i++{c<-i//阻塞,直到數(shù)據(jù)被消費者取走后才能發(fā)送下一條數(shù)}}funcconsumer(c,fchan{forifv,ok:=<-c;ok //阻塞,直到生產(chǎn)者放入數(shù)據(jù)后繼續(xù)取}else}}}funcmain()buf:=make(chan:=make(chan43)go) //等待數(shù)據(jù)接收完}consummerrangefuncfuncconsumer(c,fchan{forv:=rangec{}}funcproducer(cchan<-{funcproducer(cchan<-{deferclose(c)//關(guān)閉channelfori0i10i++{c<-i//阻塞,直到數(shù)據(jù)被消費者取走后才能發(fā)送下一條數(shù)}}funcconsumer(c<-chanint,fchan<-{forv:=rangec{}Channel可以是帶緩沖的。 第二個參數(shù)做為緩沖長度來初始化一個帶緩沖funcmain()c:=make(chanint,2)c<-1 fmt.Println(<-fmt.Println(<-c)//此時若再從c中取數(shù)據(jù),將出現(xiàn)阻塞,運 }44如果有多個channel需 ,可以考慮用select,隨機處理一個可用的channelfuncfuncfibonacci(c,quitchan{x,y:=0,for{casec<-x,y=y,x+ycase<-quit:}}}funcmain()c:=make(chanint)quit:=make(chanint)gofunc(){fori:=0;i<10;}quit<-}當(dāng)一channelread/write阻塞時,會一直被阻塞下去channel關(guān)閉,產(chǎn)生一個異常退出程序。Channel內(nèi)部沒有超時的定時器。但我們可以用select來實現(xiàn)channel的超時機importimport)funcmain()select{case<-c://因為沒有向c發(fā)送數(shù)據(jù),所以會一直阻fmt.Print("收到數(shù)據(jù)}}45進程同 共享資源。Go中的互syncimport()typeMyMapstruct mutex*sync.Mutex}func(this*MyMap)Get(keystring)(int,{thismutex.Lock()i,ok:=this.mp[key]thismutex.Unlock()if!ok{}returni,}func(this*MyMap)Set(keystring,v{thisthismp[key]=v}{thisfork,v:=range{fmt.Println(k,"=",}}{vara46}a=fori:=0;i<10;{m.Set(string(a+rune(i)),}}funcmain()m&MyMap{mp:make(map[string]intmutex:new(sync.Mutex)}goSetValue(m)/*啟動一個線程向map寫入值*/雖然我們賦值時,是按123進行的,但多次運行的結(jié)果,發(fā)現(xiàn),map的順序是不一樣,因map是無序的。只要在讀的時候不要有寫的線程。這就是讀寫鎖。讀寫鎖充許多個線程同時讀,所以并發(fā)性更好。讀寫鎖具有以下特性:多個讀操作可以同時寫必須互斥,不充許兩個寫操作同時進行,也不能讀、寫操作同時進行寫優(yōu)先于讀。在當(dāng)前線程以讀模式加鎖后,其它線程進行讀模式加鎖,可以獲得讀的權(quán)限;在當(dāng)前線程以讀模式加鎖后,其它線程加寫鎖時,將會堵塞,并且后繼的讀鎖將會堵塞。這樣可以避免讀模式鎖長期占用,導(dǎo)致寫操作一直阻塞.下面的例子可以改成讀寫鎖的實typetypeMyMapstruct }func(this*MyMap)Get(keystring)(int,{this.mutex.RLock()i,ok:=this.mp[key]if!ok{}returni,}{fork,v:=rangethismp{47}}}}funcmain()}48日期的獲取與計import)func{}Time包定義了所有時間import)func{}Format函數(shù)把一個時間格式化為字符串,定義格式為func(tTime)Format(layoutstring),layoutGo2006代表年,01代表月,02代表日,15代表時,04代表分,05代表秒。不知2006-01-02是什么重要的日子,Go要用這種格式表。importimport)funcmain()fmt.Println(time.Now().Format("2006-01- }funcParse(layout,valuestring)(Time,error),用來把一個字符串轉(zhuǎn)換成04代表分,05代表秒。importimport)funcmain()d,err:=time.Parse("01-02-2006","06-17-iferr!={}}49import)funcmain()t:=t2:=t.Add(import)funcmain()t:=t2:=t.Add(24*time.Hour)//當(dāng)前時間加24小時,即明天的這個時間d:=t2.Sub(t) ift.Before(t2//tt2}}}}中。與NewTimer等價importimport)func{t:=<-ct=<-tm.C }50函數(shù)f是不帶任何參數(shù)和返回值的。}func{fmt.Println(time.Now())}func{fmt.Println(time.Now())varstrstringfScan(r) *這里主要是等待用戶輸入,不讓進程結(jié)束,進程結(jié)束定時器也就無效了。}import)import)funcmain()c:=time.Tick(10*import)funcmain()c:=time.Tick(10*time.Second)fort:=rangec{}}51import)func{import)func{ fmt.Println(path.Base("C:\\Windows"))/*無法識別Windows路徑分隔符,將會把C:\\Windows做為一個路徑*/fmt.Println(path.Base(strings.Replace("C:\\Windows","\\",-1)))/*把\轉(zhuǎn)換成}import)func{fmt.Println(path.Clean("/a/b/../././c"))}路path包中封裝了一些路徑相關(guān)的操作,在開始接觸文件操作之前,我們先看看路徑Linux中,路徑的格式為/user/bin路徑中的分隔符是/;Windos中的路徑格式C:\Windows路徑中的分隔符是\。而Go中,只認(rèn)/,不知道怎么回事,也許是對Windows的支持不夠好。所以要想能夠正常的使用path中的函數(shù)需要把\轉(zhuǎn)換成/。在上面的例子中,我們使strings.Replace對路徑分隔符進行了轉(zhuǎn)換,最后一個參數(shù),用來指定替換次數(shù),-1表示替換所有。funcClean(pathstringstringpath等價的短路徑。一般在路徑中出現(xiàn)./或../時path.Clean("/a/b/../c")的結(jié)果為/a/cfuncDir(pathstring)string返回路徑中 部分。也就是最后一個/前面的部分52importimport)func{/*/a/c/d*/importimport)funcmain() }funcIsAbs(pathstringbool用來判斷路徑是否絕對路徑。在Linux下如果路徑是以/開頭的是絕對路徑,如/user/bin,否則是相對路徑;Windows下,以盤符開頭的是絕對路徑,如C:\Windows\system,而Windows\system是相對路徑。importimport)func{fmt.Println(path.IsAbs("/a/b/c"))"\\""/"-1/*Go}上面代碼,第一個輸出true/a/b/c是絕對路徑;第二個輸出falseC:\Windows\system是絕對路徑,但Go好像只支持Linux格式的路徑,所以此處判斷錯誤funcJoin(elem...string)string,用來進行路徑的連接。a/bca/b/cimportimport)funcmain()fmt.Println(path.Join("a/b",53} import()funcmain()fmt.Println(path.Split("/a/b/test.txt"))/*/a/b/test.txt*/ /*/a/b/c/*/}在上面的例子中path.Split("/a/b/c/")只有 funcAbs(pathstringstringerror)用來把相對路徑轉(zhuǎn)換成絕對路徑,該函數(shù)位于path/filepath包中。importimport)func{}funcWalk(rootstring,walkFnWalkFuncerrorroot下的所有文件和子目error,path為當(dāng)前文件或文件俠的完整路徑,info是os.FileInfo結(jié)構(gòu)的表示。importimport)funcDispFile(pathstring,infoos.FileInfo,errerror) info.IsDir())return}func{filepath.Walk(".",54文件讀在io包中提供了一些文件操作的函funcCreate(namestring)(file*File,err創(chuàng)建新文件,如果文件已存在,將被截斷。新建的文件是可讀寫的。默認(rèn)權(quán)0666(Linux下文件的權(quán)限設(shè)置格式)funcOpen(namestring)(file*File,err打開已經(jīng)存在的文件,用 文件內(nèi)容。 打開的文件是只讀的。不能寫funcOpenFile(namestring,flagint,permFileMode)(file*File,errOpenFile是一個通用的函數(shù),可以用來創(chuàng)建文件,以只讀方式打開文件,以讀寫方式打flag可以是下面的取值: 當(dāng)文件不存在時創(chuàng)建文件 與O_CREATE一起使用,當(dāng)文件已經(jīng)存在時Open操作失敗O_SYNC 以同步方式打開文件。每次wrie系統(tǒng)調(diào)用后都等待實際的物理I/O完成后才返回,默認(rèn)(不使用該標(biāo)記)是使用緩沖的,也就是說每次的寫操作是寫到系統(tǒng)內(nèi)核緩沖區(qū)中,等系統(tǒng)緩沖區(qū)滿后才寫到實際設(shè)備。 如果文件已存在,打開時將會清空文件內(nèi)容。必須于O_WRONLYFileMode參數(shù)是文件的權(quán)限,只有在文件不存在,新建文件時該參數(shù)才有效。用來指定新建的文件的權(quán)了。必須跟O_CREATE配合使用。importimport)funcmain() os.OpenFile("D:新建文本文檔.txt",os.O_RDONLY|os.O_APPEND|os.O_CREATE,0666)iferr!=}buf:=make([]byte,1024)varstr55f.Seek(0,os.SEEK_SET)forn,ferr:=ifferr!=nil&&ferr!=}ifn==0}str+=}}上面的例子中,寫完文件后,要想文件內(nèi)容,需要調(diào)Seek重置文件指針,否則是內(nèi)容需要重置文件指針開文件的開頭兒。func(f*File)Seek(offsetint64,whenceint)(retint64,errSeek用來設(shè)置文件指針的位置,offet是偏移量,whence的取值可以是下面的三個 offset是相對文件開始位置的偏移量。 offset是相對文件指針當(dāng)前位置的偏移量。 offset是相對文末尾的偏移量。ioutilIOr中所有內(nèi)容。在上面的例子f.Read循環(huán)文件中使用ReadAll來代替,使代碼變得簡單。importimport)funcmain() os.OpenFile("D:新建文本文檔.txt",os.O_RDONLY|os.O_APPEND|os.O_CREATE,0666)iferr!={56}}deferbuf,err1:=ioutil.ReadAll(f)iferr1!=nil{}}ReadAll簡化了IO操作,但 文件內(nèi)容還有更簡單的方法,看下面這個函數(shù)import)funcmain()buf,errioutil.ReadFile("D:\\新建文本文檔.txt")import)funcmain()buf,errioutil.ReadFile("D:\\新建文本文檔.txt")iferr!=nil{}}向文件中寫數(shù)據(jù),如果文件不存在,將以perm權(quán)限創(chuàng)建文件importimport)funcmain()err:=ioutil.WriteFile("e:\\a.txt",[]byte("abcdefg"),0777)iferr!=nil{}else}}57遍 下的文 信息,位于OS包中。定義如下func(f*File)Readdir(nint)(fi[]FileInfo,errn>0最多返回n個文件。如個小于等零,返回importimport)funcmain()f,err:=os.OpenFile("C:\\Windows",os.O_RDONLY,0666)iferr!=nil{}arrFile,err1:=f.Readdir(0)iferr1!=nil{}fork,v:=rangearrFilefmt.Println(k,"\t",v.Name(),"\t",}}供了一個ReadDir函數(shù),定義如下:下所有的文件和 。是對File.Readdir的封裝importimport)funcmain()arrFile,err:=ioutil.ReadDir("C:\\Windows")iferr!=nil{}58forfork,v:=rangearrFilefmt.Println(k,"\t",v.Name(),"\t",}}序列化就是將對象的狀態(tài)信息轉(zhuǎn)換為可以或傳輸?shù)男问降倪^程。在序列化期間,對象將其當(dāng)前狀態(tài)寫入到臨時或持久性區(qū)。之后,可以通過從區(qū)中或反序列化對象在本節(jié)中我們僅介紹gob,列化的方法,xml,json的序列化將放在下一章中討論Gob是o中所特有的序列化技術(shù),它支持除inerfacefunctionchannel外的所有o數(shù)據(jù)類型。序列化使用Encoder,反序列化使用Decoder。我們可以把一個結(jié)構(gòu)體序列化到文件中。然后再反序列化。f,f,err:=os.Create("data.dat")iferr!=nil{}deferencode:=f.Seek(0,os.SEEK_SET)decodergob.NewDecoder(f)vars1Student",import)typeStudent{NamestringAgeint}funcmain()s:=59}}608JSONXML解XML序列化與解XmlWebService中XML將數(shù)據(jù)SOAP消息。很多接XML來傳遞數(shù)據(jù)。Go中提XML序列化的文法,位于encoding/xml包中。funcenc*EncoderEncode(vinterfaceerror可以把一個對像直接序列化到io.Writer對import()typeStudent{NamestringAgeint}funcmain()f,err:=os.Create("data.dat")iferr!=nil{}defers:=s:=",encoder:=f.Seek(0,os.SEEK_SET)decoderxml.NewDecoder(f)vars1Student}61用記事本打開data.dat,可以看到文件內(nèi)容是一段XML,如下 xml包的Marshal函數(shù)可以把一個對像直接序列化成字符importimport)typeStudent{NamestringAgeint}funcmain()s:=s:=",result,result,err:=iferr!=nil{}}上面的程序結(jié) UnMarshal可以將一個xml反序列化為對varvarsStudent}import)typeStudent{NamestringAgeint}funcmain()str:=`<?xmlversion="1.0"encoding="utf-62import)typeStudentstructXMLNamexml.Nameimport)typeStudentstructXMLNamexml.Name`xml:"student"` }typeABCstringfuncmain(){str:=`<?xmlversion="1.0"encoding="utf- varsStudent}XMLNamexml.Name`xml:"student"`指定該結(jié)構(gòu)體對應(yīng)的xml標(biāo)記,[]string[]stringimportimport)typeStudentstructXMLNamexml.Name}}typeABCstringfuncmain(){str:=`<?xmlversion="1.0"encoding="utf-<student "63varsStudent}除上面的方法,xml包還提供了其它的解析xml的文法。在.netjava中都提供三張encoding=\"utf-packageimport)typeStudent{NamestringAgeint三張encoding=\"utf-packageimport)typeStudent{NamestringAgeint}funcmain() decoder:=decoder:=varstrNamestringfor{token,err:=decoder.Token()iferr!=nil{}switcht:={case m:=xml.Star fmt.Println("Start",s strName= casecaseendelem:=xml.EndElement(t)fmt.Println("End",endelem.Name.Local)casedata:=64:",:":",:",casestr:=string(data)switchstrName{casefmt.Println("other:"fmt.Println("other:",}}}}JSONon是一種比XML更輕量級的數(shù)據(jù)交換格式,易于人們閱讀和編寫,也易于程序解析和生成。是較理想的、跨平臺的、跨語言的數(shù)據(jù)交換語言,應(yīng)用十分廣泛。o提供了對on解/s:=s:= ",encoder:=import()typeStudent{NamestringAgeint}funcmain()f,err:=os.Create("data.dat")iferr!=nil{}65f.Seek(f.Seek(0,os.SEEK_SET)decoderjson.NewDecoder(f)vars1Student}指定解/編碼時對應(yīng)的json名稱。import()typeStudentstructNamestring`json:"userName"`Ageint}funcmain()s:=s:= ",buf,err:=json.Marshal(s)iferr!=nil{}vars1Studentjson.Unmarshal(buf,&s1)}}程序運行結(jié)果為 66importimport)funcmain()str:=varvarmjson.Unmarshal([]byte(str),&m)fork,v:=rangem{switch{casecasestring:fmt.Println(k,}}} 值,Json中的所有數(shù)字(整型,浮點型)將被解析為float64,Json中的string,被解析為string類型,Json中的數(shù)組被解析為interface{}數(shù)組,Json中的空值解為67gogo9MySQLgogoMySQL驅(qū)database/driver定義了一些標(biāo)準(zhǔn)的接口,這些接口由具體的數(shù)據(jù)庫驅(qū)動程序?qū)崿F(xiàn),Go 實現(xiàn)。database/sql包提供了一些通用的方法,這里的函數(shù),多是調(diào)用了database/driver接口來實現(xiàn)的。接下來我們介紹幾個常用的數(shù)據(jù)操作的函數(shù)。這里我們僅以Mysql為例,在開始之前,我們要先安裝Mysql的驅(qū)動程序。我用的是 MySQL數(shù)據(jù)庫操作下面我們介紹一下database/sql包的幾個常用函根據(jù)driverName打開指定的數(shù)據(jù)庫。driverName驅(qū)動的名稱,dataSourceName通常包含了數(shù)據(jù)庫名,和連接信息,如服務(wù)器地址、用戶名、。不同的驅(qū)動程序,會有不同的func(db*DB)Exec(querystring,erface{})(Result,執(zhí)行一個SQL查詢,不返回任何行。通常用來執(zhí)行數(shù)據(jù)的插入,更新操作。query是要執(zhí)行的SQL語句,args是參數(shù)。執(zhí)行成功errornil。Result是一個接口,定義如下:typeResult{LastInsertId()(int64,error)} 返回最后一次自動長列的值。RowsAffected,返回所影響的行func(db*DB)Query(querystring,erface{})(*Rows,Rows用來返回的數(shù)據(jù),相當(dāng)于.NetSqlDataReader,需要在數(shù)據(jù)庫連接的情況下讀數(shù)據(jù)。也就是在我們關(guān)閉連接前數(shù)據(jù)。func(r*Row)Scan(erface{})用來從返回的數(shù)據(jù)中,取數(shù)據(jù)varvaridvarnamestring68func(db*DB)QueryRow(querystring,erface{})下面我們新建一張表,然后進行插入 操作。表結(jié)構(gòu)如下CREATETABLE`name`varchar(255)DEFAULTPRIMARYKEY(`id`) DEFAULT`packageimportpackageimport_/go-sql-)funcmain() iferr!=r)return}defervarresult values(?,?,?)"," ",19,true)iferr!=r)return}lastId,_:=result.LastInsertId()varrow*sql.Rowvarnamerow=db.QueryRow(varname69packagepackageimport_/go-sql-varid,ageintvarisBoyboolerr=row.Scan(&id,&name,&age,iferr!=}fmt.Println(id,"\t",name,"\t",age,"\t", iferr!=iferr!=nil{}for{varnamestringvarid,ageintvarisBoyboolrows.Scan(&id,&name,&age,fmt.Println(id,"\t",name,"\t",age,"\t",}varrows",18,rows,err=db.Query("select*db.Exec(db.Exec("truncate注意,Query返回的rows,取完數(shù)據(jù)后需要調(diào)用Close來釋放資源func(db*DB)Prepare(querystring)(*Stmt,10000Prepare了,可70)iferr!=}deferdb.Close()varsmt*sql.Stmt iferr!=}fmt.Println("開始插入數(shù)據(jù)....",r:=rand.New(rand.NewSource(time.Now().UnixNano()))fori:=0;i<10000;i++{_,errsmt.Exec(fmt.Sprintf(%d"r.Int()),r.Intn(50),iferr!={)}}fmt.Println("數(shù)據(jù)插入完成!",插入一萬條,我這里用了22分鐘, 事 func(db*DB)Begin()(*Tx,開始一個事務(wù)71func(tx*Tx)Commit()提交事務(wù)func(tx*Tx)Rollback()用來回滾一個事務(wù)。Tx還有Query,QueryRow,,Prepare,Exec,這些用法跟DB對像的樣importimport_/go-sql-})funcmain()iferr!=nil}deferdb.Close()vartrans*sql.Txtrans,err=db.Begin()iferr!=nil{} trans.Rollback事務(wù)insert插入的數(shù)據(jù)不會真正寫到數(shù)據(jù)里。改成mit()可以將數(shù)據(jù)寫入到數(shù)據(jù)庫中。通常是根據(jù)SQL執(zhí)行的結(jié)果,來判斷iferr!={}else}(name,age,IsBoy)values('_,err=72limitpackageimportlimitpackageimport_ /go-sql-)funcmain()db,err:=sql.Open("mysql",iferr!=nil}defervarrowrow,row,err=db.Query("select*//SCanvarid,name,age,isBoyerr=row.Scan(&id,&name,&age,iferr!=nil}fmt.Println("id",id,fmt.Println("name",name,}}}[idnameageIsBoy]<nil>id[49]1name[229188160228184[idnameageIsBoy]<nil>id[49]1name[22918816022818473樣看來,列名,可以跟Scan里的值一一對應(yīng)了。按列名返回字段值,應(yīng)該可以Scanfuncfunc(rs*Rows)Scan(erface{})errorfori,sv:=rangers.lastcolsiferr!=nil{returnfmt.Errorf("sql:Scanerroroncolumnindex%d:%v",i,}}return}Rs.ascols是當(dāng)前行,所有列的值。Dest是我們傳進來的參數(shù)。在26節(jié)中我們 ,變參其實就是一個slce,dest就是一個slce,里面存放的是我們傳進來的參數(shù)。convertAssgn用來把列中的數(shù)據(jù)轉(zhuǎn)換成我們需要的類型。該函數(shù)位于go\rc\pkgdatabaesqlconvertgo文我們有兩種實現(xiàn)方式,一種是直接改daabae/sql包中的Rows給一數(shù)另在自己創(chuàng)建的程序中進行一層封裝,來提供這個功能。我們用后一種實現(xiàn)方,通常情況下,不要改系統(tǒng)文件。下面我們實現(xiàn)一個自己的Rows結(jié)構(gòu)體。}valuesmap用來存放當(dāng)前行的數(shù)據(jù),key是列名,區(qū)分大小寫;value是列對應(yīng)的數(shù)據(jù)columnName是列名。接下來我們重寫Next函數(shù),在這里把每列的數(shù)據(jù)取出來放到map中funcfunc(this*MyRows)Next(){bResult:=this.Rows.Next()ifbResult{//如果成功,取所有列的數(shù)據(jù)到valuesifthis.columnName==nil||len(this.columnName)=={this.columnName,_=}ifthis.values==nilthis.values=}vararrfori:=0;i<len(this.col

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論