版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
Go語言編程教學(xué)課件Go語言簡介Go語言(也稱為Golang)由Google公司的RobertGriesemer、RobPike和KenThompson于2007年開始設(shè)計(jì),并于2009年正式發(fā)布。作為一種開源的編程語言,Go語言旨在提高大型軟件系統(tǒng)的開發(fā)效率。Go語言的設(shè)計(jì)理念是:簡潔:語法簡單明了,減少復(fù)雜性和冗余高效:編譯速度快,運(yùn)行性能接近C/C++安全:內(nèi)置垃圾回收,減少內(nèi)存錯(cuò)誤并發(fā):從語言層面支持并發(fā)編程Go語言結(jié)合了低級語言的性能與高級語言的開發(fā)效率,在保持靜態(tài)類型和編譯型語言特性的同時(shí),提供了類似動(dòng)態(tài)語言的開發(fā)體驗(yàn)。它不僅完全開源,而且擁有跨平臺(tái)支持,可以在Windows、MacOS和各種Linux/Unix系統(tǒng)上運(yùn)行。Go語言的吉祥物是一只名為"Gopher"的地鼠,象征著這門語言的簡單友好和高效挖掘解決問題的能力。Go語言的設(shè)計(jì)目標(biāo)是創(chuàng)建一種適合現(xiàn)代多核計(jì)算機(jī)和網(wǎng)絡(luò)環(huán)境的編程語言,同時(shí)避免其他語言中的復(fù)雜性。14年發(fā)展歷史自2009年發(fā)布以來的持續(xù)發(fā)展時(shí)間2.4M+開發(fā)者全球Go語言活躍開發(fā)者數(shù)量200K+開源項(xiàng)目Go語言應(yīng)用場景云計(jì)算與微服務(wù)Go語言在云計(jì)算領(lǐng)域取得了巨大成功,最著名的例子是容器編排平臺(tái)Kubernetes和容器化技術(shù)Docker,這兩個(gè)項(xiàng)目徹底改變了現(xiàn)代應(yīng)用部署方式。Go語言的高并發(fā)性能和低資源占用使其成為微服務(wù)架構(gòu)的理想選擇,能夠高效處理大量并發(fā)請求。Kubernetes:容器編排平臺(tái),管理分布式應(yīng)用Docker:容器化平臺(tái),簡化應(yīng)用部署Istio:服務(wù)網(wǎng)格,管理微服務(wù)通信網(wǎng)絡(luò)服務(wù)器與分布式系統(tǒng)Go語言為構(gòu)建高性能網(wǎng)絡(luò)服務(wù)器提供了出色的支持,標(biāo)準(zhǔn)庫中的net/http包使開發(fā)HTTP服務(wù)變得簡單高效。許多公司使用Go構(gòu)建API服務(wù)器、Web應(yīng)用后端和大規(guī)模分布式系統(tǒng),能夠輕松處理高并發(fā)負(fù)載。Traefik:現(xiàn)代HTTP反向代理和負(fù)載均衡器Caddy:具有自動(dòng)HTTPS功能的Web服務(wù)器etcd:分布式鍵值存儲(chǔ),用于配置管理命令行工具與自動(dòng)化腳本Go語言編譯生成的是靜態(tài)二進(jìn)制文件,無需解釋器或運(yùn)行時(shí)依賴,使其成為開發(fā)命令行工具和自動(dòng)化腳本的絕佳選擇。單一可執(zhí)行文件便于分發(fā)和部署,跨平臺(tái)支持使開發(fā)者能夠輕松構(gòu)建在不同操作系統(tǒng)上運(yùn)行的工具。Hugo:世界上最快的靜態(tài)網(wǎng)站生成器Prometheus:監(jiān)控系統(tǒng)和時(shí)間序列數(shù)據(jù)庫Terraform:基礎(chǔ)設(shè)施即代碼工具開發(fā)環(huán)境搭建概覽Go語言環(huán)境搭建相對簡單,官方提供了完整的安裝包和詳細(xì)的文檔。無論您使用何種操作系統(tǒng),都可以輕松配置Go開發(fā)環(huán)境。以下是開發(fā)環(huán)境搭建的基本步驟和注意事項(xiàng):下載安裝包訪問Go語言官方網(wǎng)站()或中國鏡像站(),下載適合您操作系統(tǒng)的安裝包。Go提供了Windows、MacOS和Linux等各種平臺(tái)的安裝包。安裝Go語言按照官方指南安裝Go語言。Windows用戶運(yùn)行MSI安裝文件,MacOS用戶可以使用pkg安裝包或Homebrew,Linux用戶可以使用包管理器或tar包安裝。配置環(huán)境變量設(shè)置GOPATH(工作目錄)和GOROOT(Go安裝目錄)環(huán)境變量,并將Go的bin目錄添加到PATH環(huán)境變量中,使Go命令可以在任何目錄下執(zhí)行。選擇并配置IDE選擇適合的開發(fā)工具,如VSCode、GoLand或LiteIDE等,安裝相關(guān)Go語言插件,配置代碼補(bǔ)全、格式化和調(diào)試功能。推薦的開發(fā)工具VisualStudioCode輕量級、免費(fèi)、功能強(qiáng)大的編輯器,搭配Go插件使用GoLandJetBrains開發(fā)的專業(yè)GoIDE,功能全面但需付費(fèi)LiteIDE專為Go語言設(shè)計(jì)的開源集成開發(fā)環(huán)境Vim/Neovim配合Go插件使用的傳統(tǒng)文本編輯器,適合命令行愛好者SublimeText高性能文本編輯器,通過插件支持Go開發(fā)驗(yàn)證安裝:完成安裝后,打開命令行終端,輸入goversion命令檢查安裝是否成功。如果顯示Go版本信息,說明安裝成功。Windows環(huán)境安裝配置Windows系統(tǒng)Go語言安裝步驟訪問官方網(wǎng)站/dl/下載Windows版Go安裝包(.msi文件)雙擊MSI文件運(yùn)行安裝向?qū)В凑仗崾就瓿砂惭b默認(rèn)安裝路徑通常為C:\Go,建議使用默認(rèn)設(shè)置安裝程序會(huì)自動(dòng)將Go添加到PATH環(huán)境變量中環(huán)境變量配置Go語言在Windows系統(tǒng)上需要配置以下關(guān)鍵環(huán)境變量:GOROOT:指向Go語言安裝目錄,通常為C:\GoGOPATH:指向您的Go工作空間,推薦設(shè)置為%USERPROFILE%\goPATH:需要包含%GOROOT%\bin和%GOPATH%\bin目錄配置環(huán)境變量的步驟:右鍵點(diǎn)擊"此電腦"或"我的電腦",選擇"屬性"點(diǎn)擊"高級系統(tǒng)設(shè)置",然后點(diǎn)擊"環(huán)境變量"按鈕在"系統(tǒng)變量"部分,添加或修改GOROOT和GOPATH編輯PATH變量,確保包含Go的bin目錄驗(yàn)證安裝打開命令提示符(cmd)或PowerShell,輸入以下命令驗(yàn)證Go是否安裝成功:goversion如果顯示類似下面的輸出,說明安裝成功:goversiongo1.20.1windows/amd64檢查環(huán)境變量配置是否正確:goenv這將顯示所有Go相關(guān)的環(huán)境變量設(shè)置。目錄結(jié)構(gòu)設(shè)置在GOPATH目錄下,創(chuàng)建以下三個(gè)子目錄:src:存放源代碼文件pkg:存放編譯后的包文件bin:存放可執(zhí)行文件可以通過以下命令創(chuàng)建目錄結(jié)構(gòu):MacOS與Linux安裝配置MacOS系統(tǒng)安裝Go在MacOS系統(tǒng)上,有多種方式安裝Go語言:方法一:使用Homebrew安裝(推薦)Homebrew是MacOS上流行的包管理工具,使用它安裝Go非常簡便:打開終端應(yīng)用如果尚未安裝Homebrew,請先安裝:/bin/bash-c"$(curl-fsSL/Homebrew/install/HEAD/install.sh)"使用Homebrew安裝Go:brewinstallgo方法二:使用官方安裝包訪問下載MacOS安裝包(.pkg文件)雙擊pkg文件運(yùn)行安裝向?qū)О凑仗崾就瓿砂惭bLinux系統(tǒng)安裝Go在Linux系統(tǒng)上安裝Go的常用方法:方法一:使用包管理器Ubuntu/Debian:sudoaptupdatesudoaptinstallgolang-goCentOS/RHEL/Fedora:sudodnfinstallgolang方法二:使用官方二進(jìn)制包(推薦,獲取最新版本)下載最新的Go二進(jìn)制包:wget/dl/go1.20.1.linux-amd64.tar.gz解壓到/usr/local目錄:sudotar-C/usr/local-xzfgo1.20.1.linux-amd64.tar.gz環(huán)境變量配置在MacOS和Linux系統(tǒng)上,需要配置以下環(huán)境變量:編輯~/.bashrc或~/.zshrc文件(取決于您使用的shell),添加以下內(nèi)容:exportGOROOT=/usr/local/go#或Homebrew安裝位置exportGOPATH=$HOME/goexportPATH=$PATH:$GOROOT/bin:$GOPATH/bin使環(huán)境變量生效:source~/.bashrc#或source~/.zshrc驗(yàn)證安裝在終端中運(yùn)行以下命令,檢查Go是否正確安裝:goversion創(chuàng)建Go工作目錄結(jié)構(gòu):第一個(gè)Go程序:HelloWorldGo程序的基本結(jié)構(gòu)每個(gè)Go源文件都以包聲明開始,指定該文件屬于哪個(gè)包。可執(zhí)行程序必須包含一個(gè)名為main的包和一個(gè)main()函數(shù),這是程序的入口點(diǎn)。以下是一個(gè)最簡單的Go程序-HelloWorld://hello.gopackagemainimport"fmt"funcmain(){fmt.Println("你好,世界!")}代碼解析packagemain:聲明這個(gè)文件屬于main包,表示這是一個(gè)可執(zhí)行程序而非庫import"fmt":導(dǎo)入fmt包,它提供格式化輸入輸出的功能funcmain():定義main函數(shù),程序從這里開始執(zhí)行fmt.Println():調(diào)用fmt包中的Println函數(shù)打印文本到控制臺(tái)編譯與運(yùn)行Go提供了多種方式編譯和運(yùn)行程序:方法一:直接運(yùn)行g(shù)orunhello.go這個(gè)命令會(huì)編譯并立即運(yùn)行程序,適合開發(fā)階段使用。方法二:編譯成可執(zhí)行文件gobuildhello.go這個(gè)命令會(huì)編譯程序并生成一個(gè)可執(zhí)行文件。在Windows上生成hello.exe,在MacOS/Linux上生成hello。然后可以直接運(yùn)行這個(gè)可執(zhí)行文件:./hello#MacOS/Linuxhello.exe#Windows方法三:安裝到GOPATH的bin目錄goinstall這個(gè)命令會(huì)編譯程序并將可執(zhí)行文件放到GOPATH/bin目錄下。Go語言工具鏈命令gorun編譯并運(yùn)行Go程序gobuild編譯Go程序goinstall編譯并安裝Go程序gofmt格式化Go源代碼gotest運(yùn)行測試gomod基礎(chǔ)語法:變量聲明與賦值變量聲明方式Go語言提供了多種變量聲明和初始化的方法:1.使用var關(guān)鍵字聲明//基本語法var變量名類型//示例varnamestringvarageintvarisActivebool2.聲明并初始化//聲明變量并賦初值varnamestring="張三"varageint=25varsalaryfloat64=5000.50//類型推斷(省略類型)varname="張三"http://編譯器自動(dòng)推斷為string類型varage=25//編譯器自動(dòng)推斷為int類型3.短變量聲明(:=)這是在函數(shù)內(nèi)部最常用的聲明方式://短變量聲明,只能在函數(shù)內(nèi)部使用name:="張三"age:=25isActive:=true4.多變量聲明//一次聲明多個(gè)同類型變量vari,j,kint//一次聲明多個(gè)不同類型變量var(namestringageintsalaryfloat64)//多變量聲明并初始化vari,j,kint=1,2,3varname,age="張三",25//短變量形式name,age:="張三",25基本數(shù)據(jù)類型類型分類具體類型說明整數(shù)類型int根據(jù)系統(tǒng)架構(gòu),32位或64位int88位有符號整數(shù)(-128到127)int1616位有符號整數(shù)int32/rune32位有符號整數(shù)int6464位有符號整數(shù)無符號整數(shù)uint根據(jù)系統(tǒng)架構(gòu),32位或64位uint8/byte8位無符號整數(shù)(0到255)uint1616位無符號整數(shù)uint3232位無符號整數(shù)uint6464位無符號整數(shù)浮點(diǎn)數(shù)float3232位浮點(diǎn)數(shù)float6464位浮點(diǎn)數(shù)(默認(rèn))復(fù)數(shù)complex6432位實(shí)部和虛部complex12864位實(shí)部和虛部布爾booltrue或false字符串stringUTF-8編碼的字符序列零值(默認(rèn)值)在Go中,未初始化的變量會(huì)被自動(dòng)賦予其類型的零值:數(shù)值類型(int,float等):0布爾類型:false字符串:""(空字符串)常量與枚舉模擬常量聲明常量是在編譯時(shí)就確定的值,運(yùn)行期間不能修改。Go使用const關(guān)鍵字聲明常量://基本語法const常量名類型=值//示例constPifloat64=3.14159constMaxConnections=1000constGreeting="你好"http://類型可以省略,由編譯器推斷constPi=3.14159constMaxConnections=1000常量組多個(gè)常量可以一起聲明在一個(gè)const塊中:const(Pi=3.14159E=2.71828StatusOK=200StatusNotFound=404Prefix="GO_")無類型常量Go的常量可以是無類型的(untyped),這使它們更加靈活:const(Pi=3.14159//無類型浮點(diǎn)常量Size=100//無類型整型常量Name="Go"http://無類型字符串常量)varffloat32=Pi//合法,Pi可以賦值給float32variint=Size//合法,Size可以賦值給intiota與枚舉Go語言沒有內(nèi)置的枚舉類型,但可以使用iota標(biāo)識(shí)符來模擬枚舉。iota在const塊中會(huì)自動(dòng)遞增:const(Sunday=iota//0Monday//1Tuesday//2Wednesday//3Thursday//4Friday//5Saturday//6)iota在每個(gè)const關(guān)鍵字出現(xiàn)時(shí)重置為0,并在每個(gè)常量聲明后遞增:const(a=iota//0b//1c//2)const(d=iota//0(重置)e//1)iota的高級用法iota可以用在表達(dá)式中,實(shí)現(xiàn)更復(fù)雜的枚舉值:const(_=iota//0,忽略第一個(gè)值KB=1<<(10*iota)//1<<10=1024MB//1<<20=1048576GB//1<<30=1073741824TB//1<<40=1099511627776)const(Open=1<<iota//1<<0=1Close//1<<1=2Pending//1<<2=4Processing//1<<3=8)這種方式可以用于定義位掩碼(bitmask),便于使用按位操作:運(yùn)算符與表達(dá)式算術(shù)運(yùn)算符運(yùn)算符描述示例+加法a+b-減法a-b*乘法a*b/除法a/b%取模(余數(shù))a%b關(guān)系運(yùn)算符運(yùn)算符描述示例==等于a==b!=不等于a!=b>大于a>b<小于a<b>=大于等于a>=b<=小于等于a<=b邏輯運(yùn)算符運(yùn)算符描述示例&&邏輯與a&&b||邏輯或a||b!邏輯非!a位運(yùn)算符運(yùn)算符描述示例&按位與a&b|按位或a|b^按位異或a^b<<左移a<<n>>右移a>>n&^位清除(ANDNOT)a&^b賦值運(yùn)算符運(yùn)算符描述等價(jià)形式=簡單賦值a=b+=加法賦值a=a+b-=減法賦值a=a-b*=乘法賦值a=a*b/=除法賦值a=a/b%=取模賦值a=a%b<<=左移賦值a=a<<b>>=右移賦值a=a>>b&=按位與賦值a=a&b|=按位或賦值a=a|b^=按位異或賦值a=a^b其他運(yùn)算符運(yùn)算符描述示例&取地址&a*指針解引用*a<-通道操作符控制結(jié)構(gòu):分支語句if語句Go語言的if語句不需要圓括號,但花括號是必須的://基本形式if條件表達(dá)式{//條件為true時(shí)執(zhí)行的代碼}//示例ifage>=18{fmt.Println("成年人")}if-else語句//if-else基本形式if條件表達(dá)式{//條件為true時(shí)執(zhí)行的代碼}else{//條件為false時(shí)執(zhí)行的代碼}//示例ifscore>=60{fmt.Println("及格")}else{fmt.Println("不及格")}if-elseif-else語句//多條件判斷if條件表達(dá)式1{//條件1為true時(shí)執(zhí)行的代碼}elseif條件表達(dá)式2{//條件2為true時(shí)執(zhí)行的代碼}elseif條件表達(dá)式3{//條件3為true時(shí)執(zhí)行的代碼}else{//所有條件都為false時(shí)執(zhí)行的代碼}//示例ifscore>=90{fmt.Println("優(yōu)秀")}elseifscore>=75{fmt.Println("良好")}elseifscore>=60{fmt.Println("及格")}else{fmt.Println("不及格")}帶初始化語句的ifGo語言的if語句支持在條件判斷之前執(zhí)行一個(gè)簡單的語句://基本形式if初始化語句;條件表達(dá)式{//條件為true時(shí)執(zhí)行的代碼}//示例iferr:=doSomething();err!=nil{//處理錯(cuò)誤fmt.Println("發(fā)生錯(cuò)誤:",err)}這種形式非常適合處理函數(shù)返回的錯(cuò)誤,變量err的作用域僅限于if語句塊內(nèi)。switch語句Go的switch語句比其他語言更靈活,case無需break(默認(rèn)自動(dòng)break),多個(gè)條件可以用逗號分隔://基本形式switch表達(dá)式{case值1://代碼1case值2,值3://代碼2default://默認(rèn)代碼}//示例switchday{case"星期一":fmt.Println("開始工作了")case"星期六","星期日":fmt.Println("周末休息")default:fmt.Println("工作日")}不帶表達(dá)式的switchGo允許switch后面不跟表達(dá)式,此時(shí)相當(dāng)于switchtrue://示例switch{casescore>=90:fmt.Println("優(yōu)秀")casescore>=75:fmt.Println("良好")casescore>=60:fmt.Println("及格")default:fmt.Println("不及格")}fallthrough關(guān)鍵字如果需要執(zhí)行下一個(gè)case,可以使用fallthrough關(guān)鍵字:控制結(jié)構(gòu):循環(huán)語句for循環(huán)Go語言中只有一種循環(huán)結(jié)構(gòu):for循環(huán)。但它有多種形式,幾乎可以實(shí)現(xiàn)所有循環(huán)需求。1.標(biāo)準(zhǔn)for循環(huán)//基本語法for初始化語句;條件表達(dá)式;后置語句{//循環(huán)體}//示例fori:=0;i<5;i++{fmt.Println(i)}//輸出:012342.類似while的for循環(huán)//基本語法for條件表達(dá)式{//循環(huán)體}//示例i:=0fori<5{fmt.Println(i)i++}//輸出:012343.無限循環(huán)//基本語法for{//循環(huán)體if條件{break//跳出循環(huán)}}//示例i:=0for{fmt.Println(i)i++ifi>=5{break}}//輸出:01234range遍歷Go提供了range關(guān)鍵字,用于遍歷數(shù)組、切片、字符串、map和通道。1.遍歷數(shù)組或切片//基本語法for索引,值:=range集合{//使用索引和值}//示例nums:=[]int{10,20,30,40,50}fori,num:=rangenums{fmt.Printf("索引:%d值:%d\n",i,num)}2.僅使用索引或值//僅使用索引fori:=rangenums{fmt.Printf("索引:%d\n",i)}//僅使用值for_,num:=rangenums{fmt.Printf("值:%d\n",num)}使用下劃線(_)可以忽略不需要的變量。3.遍歷字符串//遍歷字符串,獲取Unicode字符str:="你好,世界!"fori,char:=rangestr{fmt.Printf("位置:%d字符:%cUnicode:%d\n",i,char,char)}注意:遍歷字符串時(shí),索引是按字節(jié)計(jì)算的,每個(gè)中文字符占3個(gè)字節(jié)。4.遍歷map//遍歷map獲取鍵值對m:=map[string]int{"蘋果":5,"香蕉":8,"橙子":3}forkey,value:=rangem{fmt.Printf("水果:%s數(shù)量:%d\n",key,value)}break和continuebreak:跳出當(dāng)前循環(huán)continue:跳過當(dāng)前循環(huán)剩余部分,進(jìn)入下一次迭代數(shù)組與切片數(shù)組(Array)數(shù)組是具有固定長度的一組同類型數(shù)據(jù)的集合。1.數(shù)組聲明與初始化//聲明數(shù)組vararr[5]int//長度為5的整型數(shù)組,默認(rèn)值都為0//聲明并初始化vararr=[5]int{1,2,3,4,5}//短變量聲明arr:=[5]int{1,2,3,4,5}//自動(dòng)計(jì)算長度arr:=[...]int{1,2,3,4,5}//編譯器自動(dòng)計(jì)算長度為5//指定索引位置初始化arr:=[5]int{0:10,2:30,4:50}//[10,0,30,0,50]2.多維數(shù)組//二維數(shù)組聲明varmatrix[3][4]int//二維數(shù)組初始化matrix:=[3][4]int{{0,1,2,3},{4,5,6,7},{8,9,10,11},}3.數(shù)組是值類型在Go中,數(shù)組是值類型,賦值或傳遞給函數(shù)時(shí)會(huì)復(fù)制整個(gè)數(shù)組:arr1:=[3]int{1,2,3}arr2:=arr1//arr2是arr1的完整復(fù)制arr2[0]=100//修改arr2不會(huì)影響arr1fmt.Println(arr1)//[123]fmt.Println(arr2)//[10023]切片(Slice)切片是對數(shù)組的引用,是一個(gè)動(dòng)態(tài)數(shù)組,長度可變。1.切片聲明與創(chuàng)建//聲明一個(gè)空切片vars[]int//長度為0的int切片,值為nil//使用make函數(shù)創(chuàng)建切片s:=make([]int,5)//長度為5,容量為5的切片s:=make([]int,5,10)//長度為5,容量為10的切片//通過數(shù)組切片創(chuàng)建arr:=[5]int{1,2,3,4,5}s:=arr[1:4]//[234],引用arr的部分元素//切片字面量s:=[]int{1,2,3,4,5}2.切片操作//切片追加元素s=append(s,6)//添加一個(gè)元素s=append(s,7,8,9)//添加多個(gè)元素s=append(s,s2...)//添加另一個(gè)切片的所有元素//切片容量自動(dòng)擴(kuò)展s:=make([]int,0)fori:=0;i<10;i++{s=append(s,i)fmt.Printf("長度:%d容量:%d\n",len(s),cap(s))}//切片的切片s:=[]int{1,2,3,4,5}s1:=s[1:3]//[23]s2:=s[:]//[12345],完整切片s3:=s[:3]//[123],從開始到索引3(不含)s4:=s[2:]//[345],從索引2到結(jié)束3.切片是引用類型s1:=[]int{1,2,3}s2:=s1s2[0]=100fmt.Println(s1)//[10023],s1也被修改4.切片的常用函數(shù)Map(字典)使用Map基礎(chǔ)Map是Go語言中的哈希表實(shí)現(xiàn),用于存儲(chǔ)鍵值對。1.Map聲明與創(chuàng)建//聲明一個(gè)mapvarmmap[string]int//鍵類型為string,值類型為int,此時(shí)m為nil//使用make函數(shù)創(chuàng)建mapm=make(map[string]int)//創(chuàng)建并初始化mapm:=map[string]int{"蘋果":5,"香蕉":8,"橙子":3,}map的鍵可以是任何可比較的類型,如布爾、數(shù)字、字符串、指針、通道以及僅包含這些類型的接口、結(jié)構(gòu)體和數(shù)組。不能使用切片、映射和函數(shù)作為鍵,因?yàn)樗鼈儾豢杀容^。2.基本操作//添加或修改元素m["葡萄"]=10m["蘋果"]=7//修改已有鍵的值//獲取元素count:=m["蘋果"]//獲取鍵"蘋果"對應(yīng)的值//判斷鍵是否存在count,exists:=m["西瓜"]ifexists{fmt.Printf("西瓜的數(shù)量是:%d\n",count)}else{fmt.Println("沒有西瓜")}//刪除元素delete(m,"香蕉")//從map中刪除鍵"香蕉"及其對應(yīng)的值Map的遍歷使用range關(guān)鍵字可以遍歷map中的鍵值對://遍歷所有鍵值對forkey,value:=rangem{fmt.Printf("%s:%d\n",key,value)}//只遍歷鍵forkey:=rangem{fmt.Println(key)}//只遍歷值for_,value:=rangem{fmt.Println(value)}注意:map的遍歷順序是隨機(jī)的,每次遍歷的順序可能不同。Map的特性與注意事項(xiàng)引用類型:map是引用類型,函數(shù)間傳遞不會(huì)創(chuàng)建副本動(dòng)態(tài)增長:map會(huì)根據(jù)需要?jiǎng)討B(tài)調(diào)整大小非并發(fā)安全:多個(gè)goroutine同時(shí)訪問同一個(gè)map會(huì)導(dǎo)致競態(tài)條件,需要使用同步機(jī)制零值:未初始化的map值為nil,不能直接賦值,必須先用make初始化嵌套Mapmap的值可以是另一個(gè)map,形成嵌套結(jié)構(gòu):函數(shù)基礎(chǔ)函數(shù)定義Go語言的函數(shù)使用func關(guān)鍵字定義://基本語法func函數(shù)名(參數(shù)列表)返回類型{//函數(shù)體return返回值}//示例:簡單函數(shù)funcadd(aint,bint)int{returna+b}//參數(shù)類型簡寫funcadd(a,bint)int{returna+b}//沒有參數(shù)和返回值的函數(shù)funcsayHello(){fmt.Println("你好,世界!")}多返回值Go語言的函數(shù)可以返回多個(gè)值,這是一個(gè)非常有用的特性://多返回值函數(shù)funcdivide(a,bfloat64)(float64,error){ifb==0{return0,errors.New("除數(shù)不能為零")}returna/b,nil}//調(diào)用多返回值函數(shù)result,err:=divide(10,2)iferr!=nil{fmt.Println("錯(cuò)誤:",err)}else{fmt.Println("結(jié)果:",result)}命名返回值Go函數(shù)可以給返回值命名,這樣在函數(shù)中就可以直接使用這些變量://命名返回值funcrectangleProps(length,widthfloat64)(area,perimeterfloat64){area=length*widthperimeter=2*(length+width)return//自動(dòng)返回命名的返回值變量}//調(diào)用a,p:=rectangleProps(5.0,4.0)fmt.Printf("面積:%.2f,周長:%.2f\n",a,p)可變參數(shù)函數(shù)Go支持可變數(shù)量的參數(shù),使用...表示://可變參數(shù)函數(shù)funcsum(numbers...int)int{total:=0for_,num:=rangenumbers{total+=num}returntotal}//調(diào)用fmt.Println(sum(1,2))//3fmt.Println(sum(1,2,3,4))//10//使用切片作為可變參數(shù)nums:=[]int{1,2,3,4,5}fmt.Println(sum(nums...))//使用...將切片展開函數(shù)作為值函數(shù)在Go中是一等公民,可以作為變量、參數(shù)或返回值://函數(shù)類型typeMathFuncfunc(int,int)int//函數(shù)作為變量varcalcFuncMathFunccalcFunc=func(a,bint)int{returna+b}result:=calcFunc(10,20)//30//函數(shù)作為參數(shù)funccompute(fnMathFunc,a,bint)int{returnfn(a,b)}result=compute(calcFunc,5,3)//8defer關(guān)鍵字defer語句會(huì)延遲函數(shù)的執(zhí)行,直到包含它的函數(shù)返回前才會(huì)被調(diào)用://defer示例funcprocessFile(filenamestring)error{f,err:=os.Open(filename)iferr!=nil{returnerr}deferf.Close()//文件會(huì)在函數(shù)返回前關(guān)閉//處理文件...returnnil}//多個(gè)defer按LIFO順序執(zhí)行(后進(jìn)先出)funcdeferDemo(){deferfmt.Println("1")deferfmt.Println("2")deferfmt.Println("3")fmt.Println("函數(shù)開始")}//輸出://函數(shù)開始//3//2//1閉包與匿名函數(shù)匿名函數(shù)Go支持匿名函數(shù),即沒有函數(shù)名的函數(shù)://定義并立即調(diào)用匿名函數(shù)func(){fmt.Println("這是一個(gè)匿名函數(shù)")}()//帶參數(shù)的匿名函數(shù)func(namestring){fmt.Printf("你好,%s\n",name)}("張三")//將匿名函數(shù)賦值給變量add:=func(a,bint)int{returna+b}fmt.Println(add(5,3))//8閉包基礎(chǔ)閉包是引用了外部變量的匿名函數(shù)。即使外部函數(shù)已經(jīng)返回,閉包仍然可以訪問并修改這些變量://簡單閉包示例funcmakeCounter()func()int{count:=0returnfunc()int{count++returncount}}//使用閉包c(diǎn)ounter:=makeCounter()fmt.Println(counter())//1fmt.Println(counter())//2fmt.Println(counter())//3//創(chuàng)建新的計(jì)數(shù)器,互不影響counter2:=makeCounter()fmt.Println(counter2())//1fmt.Println(counter())//4在這個(gè)例子中,makeCounter函數(shù)返回一個(gè)匿名函數(shù),這個(gè)匿名函數(shù)可以訪問并修改makeCounter函數(shù)中的count變量。每次調(diào)用返回的函數(shù),count都會(huì)增加,形成了一個(gè)簡單的計(jì)數(shù)器。閉包應(yīng)用實(shí)例1.函數(shù)工廠//創(chuàng)建增量函數(shù)的工廠funcmakeAdder(baseint)func(int)int{returnfunc(xint)int{returnbase+x}}//使用函數(shù)工廠add5:=makeAdder(5)add10:=makeAdder(10)fmt.Println(add5(2))//7fmt.Println(add10(2))//122.中間件模式//簡化的HTTP中間件示例typeHttpHandlerfunc(http.ResponseWriter,*http.Request)funcLogger(handlerHttpHandler)HttpHandler{returnfunc(whttp.ResponseWriter,r*http.Request){fmt.Printf("請求:%s%s\n",r.Method,r.URL.Path)startTime:=time.Now()handler(w,r)fmt.Printf("處理時(shí)間:%v\n",time.Since(startTime))}}funcHello(whttp.ResponseWriter,r*http.Request){fmt.Fprintln(w,"你好,世界!")}//使用中間件http.HandleFunc("/",Logger(Hello))3.延遲執(zhí)行//在循環(huán)中使用閉包的常見陷阱funcincorrectDelayedPrint(){fori:=1;i<=3;i++{//錯(cuò)誤方式:所有函數(shù)共享同一個(gè)i變量gofunc(){fmt.Println(i)//可能都輸出4}()}//正確方式:將i作為參數(shù)傳入fori:=1;i<=3;i++{gofunc(valint){fmt.Println(val)//輸出1,2,3(順序可能不定)}(i)}}閉包與垃圾回收閉包會(huì)持有對外部變量的引用,所以當(dāng)閉包仍在使用時(shí),這些變量不會(huì)被垃圾回收。這可能導(dǎo)致內(nèi)存使用量增加,特別是在創(chuàng)建大量閉包的情況下。指針基礎(chǔ)指針概念指針是存儲(chǔ)另一個(gè)變量內(nèi)存地址的變量。Go語言的指針簡化了C/C++中的指針操作,提供了安全性的同時(shí)保留了靈活性。指針的聲明與使用//聲明指針變量varp*int//聲明一個(gè)指向int類型的指針,初始值為nil//獲取變量的地址x:=10p=&x//p現(xiàn)在指向變量x的內(nèi)存地址//通過指針訪問值(解引用)fmt.Println(*p)//10,輸出p指向的值//通過指針修改值*p=20//修改p指向的值fmt.Println(x)//20,x的值也被修改指針的零值指針的零值是nil,表示指針不指向任何內(nèi)存地址。嘗試解引用一個(gè)nil指針會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤(panic):varp*int//p的值為nil//*p=10//錯(cuò)誤:空指針解引用會(huì)導(dǎo)致panic//安全使用指針的方式ifp!=nil{*p=10}else{//處理nil指針的情況}指針與new函數(shù)Go提供了new函數(shù)用于創(chuàng)建指針://使用new函數(shù)創(chuàng)建指針p:=new(int)//分配內(nèi)存,返回指向零值int的指針*p=10//設(shè)置值fmt.Println(*p)//10指針傳遞與值傳遞在函數(shù)調(diào)用時(shí),Go默認(rèn)使用值傳遞,意味著函數(shù)接收的是參數(shù)的副本。使用指針可以實(shí)現(xiàn)引用傳遞的效果://值傳遞:函數(shù)無法修改原始值funcincrementValue(valint){val++}//指針傳遞:函數(shù)可以修改原始值funcincrementPointer(val*int){*val++}funcmain(){x:=10incrementValue(x)fmt.Println(x)//10,x未被修改incrementPointer(&x)fmt.Println(x)//11,x被修改}指針與結(jié)構(gòu)體指針在處理結(jié)構(gòu)體時(shí)特別有用,可以避免復(fù)制大型結(jié)構(gòu)體并實(shí)現(xiàn)修改原始數(shù)據(jù)://定義結(jié)構(gòu)體typePersonstruct{NamestringAgeint}//使用值接收者的方法func(pPerson)Birthday(){p.Age++//只修改副本,原始結(jié)構(gòu)體不變}//使用指針接收者的方法func(p*Person)BirthdayPtr(){p.Age++//修改原始結(jié)構(gòu)體}funcmain(){person:=Person{Name:"張三",Age:30}person.Birthday()fmt.Println(person.Age)//30,年齡未變person.BirthdayPtr()fmt.Println(person.Age)//31,年齡增加}注意:即使方法使用指針接收者,Go也允許使用值調(diào)用方法,編譯器會(huì)自動(dòng)取地址。指針數(shù)組與數(shù)組指針結(jié)構(gòu)體與面向?qū)ο蠼Y(jié)構(gòu)體基礎(chǔ)結(jié)構(gòu)體是Go中表示復(fù)合數(shù)據(jù)類型的主要方式,可以將不同類型的數(shù)據(jù)組合在一起://定義結(jié)構(gòu)體typePersonstruct{NamestringAgeintGenderstringAddressAddress//嵌套結(jié)構(gòu)體}typeAddressstruct{CitystringCountrystring}//創(chuàng)建結(jié)構(gòu)體實(shí)例//方法1:按字段順序提供值p1:=Person{"張三",30,"男",Address{"北京","中國"}}//方法2:指定字段名(推薦,更清晰)p2:=Person{Name:"李四",Age:25,Gender:"女",Address:Address{City:"上海",Country:"中國",},}//方法3:使用new函數(shù)(返回指針)p3:=new(Person)p3.Name="王五"p3.Age=35//方法4:先聲明,再賦值varp4Personp4.Name="趙六"p4.Age=40結(jié)構(gòu)體方法Go中的方法是特殊的函數(shù),它與特定類型關(guān)聯(lián)。通過定義方法,可以為結(jié)構(gòu)體添加行為://值接收者的方法func(pPerson)GetInfo()string{returnfmt.Sprintf("%s,%d歲,來自%s",p.Name,p.Age,p.Address.City)}//指針接收者的方法(可以修改接收者)func(p*Person)SetAge(ageint){p.Age=age}結(jié)構(gòu)體嵌入(組合)Go不支持傳統(tǒng)的繼承,但可以通過嵌入結(jié)構(gòu)體實(shí)現(xiàn)類似的功能://定義基礎(chǔ)結(jié)構(gòu)體typeHumanstruct{NamestringAgeintGenderstring}//定義方法func(hHuman)Speak()string{returnfmt.Sprintf("你好,我是%s",h.Name)}//嵌入Human結(jié)構(gòu)體typeStudentstruct{Human//匿名字段,嵌入HumanSchoolstringGradeint}//Student特有的方法func(sStudent)Study()string{returnfmt.Sprintf("%s正在學(xué)習(xí)",s.Name)}//使用嵌入結(jié)構(gòu)體student:=Student{Human:Human{Name:"小明",Age:15,Gender:"男",},School:"實(shí)驗(yàn)中學(xué)",Grade:9,}//可以直接訪問嵌入結(jié)構(gòu)體的字段和方法fmt.Println(student.Name)//小明fmt.Println(student.Speak())//你好,我是小明fmt.Println(student.Study())//小明正在學(xué)習(xí)結(jié)構(gòu)體標(biāo)簽結(jié)構(gòu)體標(biāo)簽是結(jié)構(gòu)體字段的元數(shù)據(jù),常用于序列化/反序列化:typeUserstruct{IDint`json:"id"`Usernamestring`json:"username"`Emailstring`json:"email,omitempty"`CreatedAttime.Time`json:"created_at"xml:"createdAt"`}//使用標(biāo)簽進(jìn)行JSON序列化user:=User{ID:1,Username:"gopher",Email:"gopher@",CreatedAt:time.Now(),}jsonData,err:=json.Marshal(user)iferr!=nil{fmt.Println("序列化錯(cuò)誤:",err)}fmt.Println(string(jsonData))//輸出:{"id":1,"username":"gopher","email":"gopher@","created_at":"2023-01-01T12:00:00Z"}私有與公有(可導(dǎo)出)字段Go通過首字母大小寫控制結(jié)構(gòu)體字段和方法的可見性:大寫字母開頭:公有,可在包外訪問小寫字母開頭:私有,僅在包內(nèi)可見接口與多態(tài)接口基礎(chǔ)接口是Go中實(shí)現(xiàn)多態(tài)的主要機(jī)制,它定義了一組方法集而不實(shí)現(xiàn)它們://定義接口typeSpeakerinterface{Speak()string}//實(shí)現(xiàn)接口的結(jié)構(gòu)體1typeHumanstruct{Namestring}func(hHuman)Speak()string{returnfmt.Sprintf("%s說:你好!",h.Name)}//實(shí)現(xiàn)接口的結(jié)構(gòu)體2typeDogstruct{Namestring}func(dDog)Speak()string{returnfmt.Sprintf("%s說:汪汪!",d.Name)}//接口作為函數(shù)參數(shù),實(shí)現(xiàn)多態(tài)funcLet(sSpeaker){fmt.Println(s.Speak())}//使用多態(tài)human:=Human{Name:"張三"}dog:=Dog{Name:"旺財(cái)"}Let(human)//輸出:張三說:你好!Let(dog)//輸出:旺財(cái)說:汪汪!在Go中,接口的實(shí)現(xiàn)是隱式的。只要一個(gè)類型實(shí)現(xiàn)了接口中的所有方法,它就自動(dòng)滿足該接口,不需要顯式聲明。接口值接口值由兩部分組成:具體類型和該類型的值。這兩部分稱為接口的動(dòng)態(tài)類型和動(dòng)態(tài)值:varsSpeaker//接口值是nil(動(dòng)態(tài)類型和動(dòng)態(tài)值都是nil)fmt.Printf("%T%v\n",s,s)////給接口賦值s=Human{Name:"張三"}fmt.Printf("%T%v\n",s,s)//main.Human{張三}//更改接口值s=Dog{Name:"旺財(cái)"}fmt.Printf("%T%v\n",s,s)//main.Dog{旺財(cái)}空接口空接口(interface{})不包含任何方法,因此所有類型都實(shí)現(xiàn)了空接口://定義空接口typeAnyinterface{}//使用空接口作為參數(shù)(可接受任何類型)funcPrintAny(ainterface{}){fmt.Println(a)}//調(diào)用PrintAny(42)//整數(shù)PrintAny("你好")//字符串PrintAny([]int{1,2})//切片類型斷言類型斷言用于檢查接口值的動(dòng)態(tài)類型是否是指定的類型://基本語法value,ok:=interfaceValue.(Type)//示例funcprocess(iinterface{}){//方法1:帶檢查的類型斷言str,ok:=i.(string)ifok{fmt.Printf("字符串值:%s\n",str)}else{fmt.Println("不是字符串")}//方法2:類型選擇(switch)switchv:=i.(type){casestring:fmt.Printf("字符串值:%s\n",v)caseint:fmt.Printf("整數(shù)值:%d\n",v)casefloat64:fmt.Printf("浮點(diǎn)值:%f\n",v)default:fmt.Printf("未知類型:%T\n",v)}}接口組合接口可以通過嵌入其他接口來組合://定義基礎(chǔ)接口typeReaderinterface{Read(p[]byte)(nint,errerror)}typeWriterinterface{Write(p[]byte)(nint,errerror)}//組合接口typeReadWriterinterface{ReaderWriter}常用標(biāo)準(zhǔn)庫接口io.Reader:從數(shù)據(jù)源讀取數(shù)據(jù)io.Writer:向目標(biāo)寫入數(shù)據(jù)fmt.Stringer:自定義類型的字符串表示error:錯(cuò)誤接口錯(cuò)誤處理機(jī)制錯(cuò)誤處理基礎(chǔ)Go語言使用顯式的錯(cuò)誤處理而不是異常機(jī)制。函數(shù)通常返回一個(gè)錯(cuò)誤值,調(diào)用者應(yīng)該檢查這個(gè)錯(cuò)誤://error接口typeerrorinterface{Error()string}//基本錯(cuò)誤處理模式funcdoSomething()error{//操作可能失敗,返回錯(cuò)誤ifsomethingFailed{returnerrors.New("操作失敗")}returnnil//成功時(shí)返回nil}//調(diào)用并處理錯(cuò)誤err:=doSomething()iferr!=nil{//處理錯(cuò)誤fmt.Println("發(fā)生錯(cuò)誤:",err)//可能返回錯(cuò)誤或中止程序return}//繼續(xù)執(zhí)行...創(chuàng)建錯(cuò)誤Go提供了多種創(chuàng)建錯(cuò)誤的方式://使用errors包import"errors"err1:=errors.New("這是一個(gè)錯(cuò)誤")//使用fmt.Errorf格式化錯(cuò)誤消息name:="文件"err2:=fmt.Errorf("%s不存在",name)//自定義錯(cuò)誤類型typeMyErrorstruct{CodeintMessagestring}func(eMyError)Error()string{returnfmt.Sprintf("錯(cuò)誤%d:%s",e.Code,e.Message)}//創(chuàng)建自定義錯(cuò)誤err3:=MyError{Code:404,Message:"資源不存在",}錯(cuò)誤傳遞和包裝Go1.13引入了錯(cuò)誤包裝,允許在不丟失原始錯(cuò)誤的情況下添加上下文://包裝錯(cuò)誤(Go1.13+)funcreadConfig(pathstring)([]byte,error){data,err:=ioutil.ReadFile(path)iferr!=nil{returnnil,fmt.Errorf("讀取配置文件失敗:%w",err)}returndata,nil}//使用包裝的錯(cuò)誤data,err:=readConfig("config.json")iferr!=nil{//打印完整錯(cuò)誤鏈fmt.Println(err)//解包原始錯(cuò)誤varpathErr*fs.PathErroriferrors.As(err,&pathErr){fmt.Printf("文件操作錯(cuò)誤:%v\n",pathErr.Path)}//檢查特定錯(cuò)誤iferrors.Is(err,fs.ErrNotExist){fmt.Println("配置文件不存在,將使用默認(rèn)配置")}}panic與recover雖然Go推薦使用錯(cuò)誤返回值進(jìn)行錯(cuò)誤處理,但它也提供了panic和recover機(jī)制處理無法繼續(xù)執(zhí)行的異常情況://panic示例funcdivide(a,bint)int{ifb==0{panic("除數(shù)不能為零")}returna/b}//recover示例funcsafeOperation()(resultint,errerror){//使用defer+匿名函數(shù)+recover捕獲panicdeferfunc(){ifr:=recover();r!=nil{fmt.Println("捕獲到panic:",r)//將panic轉(zhuǎn)換為錯(cuò)誤返回err=fmt.Errorf("操作失敗:%v",r)}}()//可能發(fā)生panic的代碼result=divide(10,0)returnresult,nil}最佳實(shí)踐僅在無法恢復(fù)的情況下使用panic(如程序初始化失敗)優(yōu)先使用錯(cuò)誤返回值而非panic/recover在錯(cuò)誤消息中提供足夠上下文使用錯(cuò)誤包裝保留錯(cuò)誤鏈公共API應(yīng)返回具體的錯(cuò)誤類型,便于調(diào)用者識(shí)別和處理并發(fā)編程基礎(chǔ)goroutinegoroutine是Go的輕量級線程,由Go運(yùn)行時(shí)管理,比傳統(tǒng)線程更高效://啟動(dòng)goroutinefuncsayHello(){fmt.Println("你好,世界!")}//使用go關(guān)鍵字啟動(dòng)goroutinegosayHello()//函數(shù)在新的goroutine中執(zhí)行,不阻塞當(dāng)前程序//匿名函數(shù)的goroutinegofunc(){fmt.Println("在goroutine中執(zhí)行的匿名函數(shù)")}()//帶參數(shù)的goroutinegofunc(namestring){fmt.Printf("你好,%s!\n",name)}("張三")goroutine非常輕量,創(chuàng)建成千上萬個(gè)goroutine是很常見的。Go運(yùn)行時(shí)會(huì)自動(dòng)在多個(gè)操作系統(tǒng)線程上多路復(fù)用這些goroutine。channel基礎(chǔ)channel是goroutine間通信和同步的主要方式://創(chuàng)建通道ch:=make(chanint)//無緩沖通道ch2:=make(chanint,10)//緩沖通道,容量為10//發(fā)送數(shù)據(jù)到通道ch<-42//將42發(fā)送到通道//從通道接收數(shù)據(jù)value:=<-ch//從通道接收數(shù)據(jù)并賦值給value//關(guān)閉通道close(ch)//關(guān)閉通道,不能再發(fā)送數(shù)據(jù)無緩沖通道無緩沖通道的發(fā)送和接收是同步的,發(fā)送方會(huì)阻塞直到有接收方接收數(shù)據(jù)://無緩沖通道示例ch:=make(chanstring)gofunc(){fmt.Println("開始發(fā)送數(shù)據(jù)")ch<-"hello"http://阻塞,直到主goroutine接收數(shù)據(jù)fmt.Println("數(shù)據(jù)已發(fā)送")}()time.Sleep(time.Second)//等待一秒fmt.Println("準(zhǔn)備接收數(shù)據(jù)")msg:=<-ch//接收數(shù)據(jù),goroutine得以繼續(xù)fmt.Println("收到:",msg)緩沖通道緩沖通道有一個(gè)容量,發(fā)送操作在緩沖區(qū)滿時(shí)阻塞,接收操作在緩沖區(qū)空時(shí)阻塞://緩沖通道示例ch:=make(chanint,3)//容量為3的緩沖通道//發(fā)送數(shù)據(jù)(不會(huì)阻塞,因?yàn)橛凶銐蚓彌_空間)ch<-1ch<-2ch<-3//再發(fā)送會(huì)阻塞,因?yàn)榫彌_區(qū)已滿//ch<-4//此操作會(huì)阻塞//接收一個(gè)值,騰出緩沖空間<-ch//接收1//現(xiàn)在可以再發(fā)送了ch<-4通道遍歷和關(guān)閉//生產(chǎn)者gofunc(){fori:=0;i<5;i++{ch<-i}close(ch)//數(shù)據(jù)發(fā)送完畢后關(guān)閉通道}()//消費(fèi)者:使用forrange遍歷通道,直到通道關(guān)閉fornum:=rangech{fmt.Println("接收:",num)}//判斷通道是否關(guān)閉value,ok:=<-chif!ok{fmt.Println("通道已關(guān)閉")}select語句select允許在多個(gè)通道操作上等待,類似于switch但用于通道://select基本用法select{casevalue:=<-ch1://從ch1接收到數(shù)據(jù)fmt.Println("從通道1接收:",value)casech2<-42://向ch2發(fā)送成功fmt.Println("向通道2發(fā)送成功")case<-time.After(1*time.Second)://超時(shí)情況fmt.Println("操作超時(shí)")default://所有通道操作都不可行時(shí)執(zhí)行fmt.Println("沒有通道操作可行")}//使用select實(shí)現(xiàn)非阻塞通道操作select{casevalue:=<-ch://從通道接收數(shù)據(jù)fmt.Println("接收:",value)default://通道沒有可用數(shù)據(jù)fmt.Println("無數(shù)據(jù)可接收")}實(shí)際示例:工作池并發(fā)模式與競態(tài)條件常見并發(fā)模式1.生產(chǎn)者-消費(fèi)者模式funcproducer(chchan<-int){fori:=0;i<10;i++{ch<-i//發(fā)送數(shù)據(jù)time.Sleep(100*time.Millisecond)}close(ch)//生產(chǎn)完畢,關(guān)閉通道}funcconsumer(idint,ch<-chanint){forvalue:=rangech{fmt.Printf("消費(fèi)者#%d接收:%d\n",id,value)}fmt.Printf("消費(fèi)者#%d退出\n",id)}//使用模式ch:=make(chanint,5)goproducer(ch)//啟動(dòng)一個(gè)生產(chǎn)者goconsumer(1,ch)//啟動(dòng)一個(gè)消費(fèi)者goconsumer(2,ch)//啟動(dòng)另一個(gè)消費(fèi)者2.扇出-扇入模式funcgenerator(nums...int)<-chanint{out:=make(chanint)gofunc(){for_,n:=rangenums{out<-n}close(out)}()returnout}funcsquare(in<-chanint)<-chanint{out:=make(chanint)gofunc(){forn:=rangein{out<-n*n}close(out)}()returnout}funcmerge(cs...<-chanint)<-chanint{out:=make(chanint)varwgsync.WaitGroup//為每個(gè)輸入通道啟動(dòng)一個(gè)goroutineoutput:=func(c<-chanint){forn:=rangec{out<-n}wg.Done()}wg.Add(len(cs))for_,c:=rangecs{gooutput(c)}//等待所有輸入通道處理完畢后關(guān)閉輸出通道gofunc(){wg.Wait()close(out)}()returnout}競態(tài)條件競態(tài)條件是指程序的行為依賴于多個(gè)操作的執(zhí)行順序,而這個(gè)順序是不確定的://競態(tài)條件示例funcracyCounter(){counter:=0//啟動(dòng)100個(gè)goroutine,每個(gè)遞增計(jì)數(shù)器100次fori:=0;i<100;i++{gofunc(){forj:=0;j<100;j++{counter++//競態(tài)條件}}()}time.Sleep(time.Second)fmt.Println("計(jì)數(shù)器:",counter)//可能不是10000}使用互斥鎖(Mutex)解決競態(tài)條件funcsafeCounter(){varmusync.Mutexcounter:=0//啟動(dòng)100個(gè)goroutine,每個(gè)遞增計(jì)數(shù)器100次varwgsync.WaitGroupfori:=0;i<100;i++{wg.Add(1)gofunc(){forj:=0;j<100;j++{mu.Lock()counter++mu.Unlock()}wg.Done()}()}wg.Wait()fmt.Println("安全計(jì)數(shù)器:",counter)//總是10000}讀寫鎖(RWMutex)當(dāng)有多個(gè)讀操作和少量寫操作時(shí),使用讀寫鎖效率更高:funcrwLockExample(){varrwMusync.RWMutexdata:=make(map[string]int)//寫操作gofunc(){fori:=0;i<10;i++{rwMu.Lock()//寫鎖,阻塞所有讀和寫data[fmt.Sprintf("key%d",i)]=irwMu.Unlock()time.Sleep(10*time.Millisecond)}
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 食品生產(chǎn)落料處理制度
- 商品生產(chǎn)臺(tái)賬制度
- 定期安全生產(chǎn)檢查制度
- 生產(chǎn)巡檢記錄管理制度
- 糕點(diǎn)生產(chǎn)質(zhì)量管理制度
- 機(jī)務(wù)安全生產(chǎn)基本制度
- 2026北京第二外國語學(xué)院第一批非事業(yè)編制人員招聘5人參考考試試題附答案解析
- 安全生產(chǎn)管理人制度
- 蔬菜平行生產(chǎn)管理制度
- 企業(yè)生產(chǎn)車間門管理制度
- GB/T 43934-2024煤礦土地復(fù)墾與生態(tài)修復(fù)技術(shù)規(guī)范
- GB/T 13077-2024鋁合金無縫氣瓶定期檢驗(yàn)與評定
- DB4403-T 427-2024 叉車運(yùn)行監(jiān)測系統(tǒng)技術(shù)規(guī)范
- 食品殺菌原理培訓(xùn)課件
- GB/T 10739-2023紙、紙板和紙漿試樣處理和試驗(yàn)的標(biāo)準(zhǔn)大氣條件
- 神經(jīng)內(nèi)科練習(xí)題庫及答案
- GB/T 42973-2023半導(dǎo)體集成電路數(shù)字模擬(DA)轉(zhuǎn)換器
- 肝性腦病教學(xué)查房課件
- 膜式壁制造及檢驗(yàn)工藝演示文稿
- 紅壤區(qū)貧瘠農(nóng)田土壤快速培肥技術(shù)規(guī)程
- 傳染病報(bào)告卡的填寫
評論
0/150
提交評論