版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Go語言入門分享
前言
曾經(jīng)我是一名以Java語言為主的開發(fā)者,做過JavaWeb相關(guān)的開發(fā),后來轉(zhuǎn)Android,還是離不開Java,直到轉(zhuǎn)去做大前端了,其實(shí)也就是一直在用JS寫業(yè)務(wù)。如今由于個(gè)人開展原因,來到阿里云,由于工程需要就擼起了Go語言;多年編程經(jīng)驗(yàn)告訴我,語言只是工具罷了,重要的還是其思想與邏輯,所以只需學(xué)學(xué)語法就好了,于是我便三天入門Go,期間主要用Java和JS來類比,語法變化之大,差點(diǎn)讓我從入門到放棄了!其實(shí),還真不是學(xué)習(xí)語法就好了呢,其中包含了很多Go的設(shè)計(jì)理念。正所謂好記性不如敲爛鍵盤,學(xué)過的東西,還是要沉淀沉淀,也可以分享出來一起探討,更有助于成長(zhǎng),于是我就簡(jiǎn)單記錄了一下我的Go語言入門學(xué)習(xí)筆記。
一
簡(jiǎn)介
Go語言出自KenThompson、RobPike和RobertGriesemer之手,起源于2022年,并在2022年正式對(duì)外發(fā)布,其實(shí)都是Google的,設(shè)計(jì)Go語言的初衷都是為了滿足Google的需求。Go的主要目標(biāo)是“兼具Python等動(dòng)態(tài)語言的開發(fā)速度和C/C++等編譯型語言的性能與平安性〞,旨在不損失應(yīng)用程序性能的情況下降低代碼的復(fù)雜性,具有“部署簡(jiǎn)單、并發(fā)性好、語言設(shè)計(jì)良好、執(zhí)行性能好〞等優(yōu)勢(shì)。最主要還是為了并發(fā)而生,并發(fā)是基于goroutine的,goroutine類似于線程,但并非線程,可以將goroutine理解為一種虛擬線程。Go語言運(yùn)行時(shí)會(huì)參與調(diào)度goroutine,并將goroutine合理地分配到每個(gè)CPU中,最大限度地使用CPU性能。
二
環(huán)境
我們玩Java的時(shí)候需要下載JDK,類似于此,用Go開發(fā)也需要下載Go,里面提供各種develop-kit、library以及編譯器。在官網(wǎng)下載mac版本pkg后直接安裝,最后用goversion命令驗(yàn)證版本:
然后就是設(shè)置這兩個(gè)環(huán)境變量,mac系統(tǒng)是在.bash_profile文件里面:
exportGOROOT=/usr/local/go
exportGOPATH=$HOME/go
GOROOT:表示的是Go語言編譯、工具、規(guī)范庫(kù)等的安裝路徑,其實(shí)就相當(dāng)于配置JAVA_HOME那樣。
GOPATH:這個(gè)和Java有點(diǎn)不一樣,Java里并不需要設(shè)置這個(gè)變量,這個(gè)表示Go的工作目錄,是全局的,當(dāng)執(zhí)行Go命令的時(shí)候會(huì)依賴這個(gè)目錄,相當(dāng)于一個(gè)全局的workspace。一般還會(huì)把$GOPATH/bin設(shè)置到PATH目錄,這樣編譯過的代碼就可以直接執(zhí)行了。
1
純文本開發(fā)
編寫代碼,可以保留在任意地方,示例新建一個(gè)helloworld目錄,創(chuàng)立hello.go文件:
packagemain
import"fmt"
funcmain(){
fmt.Println("hello,world")
}
然后執(zhí)行g(shù)obuildhello.go就可以編譯出hello文件,在./hello就可以執(zhí)行了;或者直接gorunhello.go合二為一去執(zhí)行。執(zhí)行這個(gè)命令并不需要設(shè)置環(huán)境變量就可以了??雌饋砗蚦差不多,但是和Java不一樣,運(yùn)行的時(shí)候不需要虛擬機(jī)。早期的GO項(xiàng)目也是使用Makefile來編譯,后來有了強(qiáng)大的命令gobuild、gorun,可以直接辨認(rèn)目錄還是文件。
2
GoLand
自動(dòng)import,超爽的體驗(yàn)!不用按command+/了!
運(yùn)行工程需要設(shè)置buildconfig,和Android、Java的都差不多,示例創(chuàng)立一個(gè)hello-goland工程:
導(dǎo)入gomodule工程的時(shí)候需要勾選這項(xiàng),否那么無法像maven/gradle那樣sync下載依賴:
3
VSCODE
直接搜索Go插件,第一個(gè)最多安裝量的就是了,我還沒用過所以不太分明如何。
三
項(xiàng)目結(jié)構(gòu)
在設(shè)置GOPATH環(huán)境變量的時(shí)候,這個(gè)目錄里面又分了三個(gè)子目錄bin、pkg、src,分別用于寄存可執(zhí)行文件、包文件和源碼文件。當(dāng)我們執(zhí)行Go命令的時(shí)候,如果我們指定的不是當(dāng)前目錄的文件或者絕對(duì)路徑的目錄的話,就會(huì)去GOPATH目錄的去找。這樣在GOPATH目錄創(chuàng)立了xxx的目錄后,就可以在任意地方執(zhí)行g(shù)obuildxx命令來構(gòu)建或者運(yùn)行了。
pkg目錄應(yīng)該是在執(zhí)行g(shù)oinstall后生成的包文件,包括.a這樣的文件,相當(dāng)于一個(gè)歸檔。
├──bin
│
├──air
│
├──govendor
│
├──swag
│
└──wire
├──pkg
│
├──darwin_amd64
│
├──mod
│
└──sumdb
└──src
├──calc
├──gin-blog
├──github
├──
├──
├──gopkg.in
└──simplemath
這樣對(duì)于我們具體工程來說并不好,沒有Workspace的概念來隔離每個(gè)工程了,所以我覺得這個(gè)GOPATH目錄放的應(yīng)該是公用的工程,示例開源依賴的。我們?cè)陂_發(fā)過程中,也會(huì)下載很多的依賴,這些依賴都下載到這個(gè)目錄,和我們的工程文件混在一起了。
另外,通過IDE可以設(shè)置project的GOPATH,相當(dāng)于在執(zhí)行的時(shí)候給GOPATH增加了一個(gè)目錄變量,也就是說,我們創(chuàng)立一個(gè)工程,然后里面也有bin、src、pkg這三個(gè)目錄,和GOPATH一樣的,本質(zhì)上,IDE在運(yùn)行的時(shí)候其實(shí)就是設(shè)置了一下GOPATH:
GOPATH=/Users/fuxing/develop/testgo/calc-outside:/Users/fuxing/develop/go#gosetup
Go語言在尋找變量、函數(shù)、類屬性及辦法的時(shí)候,會(huì)先查看GOPATH這個(gè)系統(tǒng)環(huán)境變量,然后根據(jù)該變量配置的路徑列表依次去對(duì)應(yīng)路徑下的src目錄下根據(jù)包名查找對(duì)應(yīng)的目錄,如果對(duì)應(yīng)目錄存在,那么再到該目錄下查找對(duì)應(yīng)的變量、函數(shù)、類屬性和辦法。
其實(shí)官方提供了GoModules的辦法更好解決。
1
GoModules
從Go1.11版本開始,官方提供了GoModules管理工程和依賴,從1.13版本開始,更是默認(rèn)開啟了對(duì)GoModules的支持,使用GoModules的好處是顯而易見的——不需要再依賴GOPATH,你可以在任何位置創(chuàng)立Go工程,并且在國(guó)內(nèi),可以通過GOPROXY配置鏡像源加速依賴包的下載。也就是說,創(chuàng)立一個(gè)工程就是一個(gè)mod,根本上目前Go開源工程都是這樣做的。其實(shí)就是類似于Maven和Gradle。
//創(chuàng)立mod工程,也是可以用IDE來new一個(gè)mod工程的:
gomodinitcalc-mod
//一般開源在github上面的工程名字是這樣的;和maven、gradle不一樣的是,開發(fā)完成基本不需要發(fā)布到倉(cāng)庫(kù)!只要提交代碼后打tag就可以了
gomodinitgithub/fuxing-repo/fuxing-module-name
//創(chuàng)立一個(gè)模塊:執(zhí)行這個(gè)命令主要是多了一個(gè)go.mod文件,里面就一行內(nèi)容:
modulecalc-mod
//import以后,執(zhí)行下載依賴命令,不需要編輯go.mod文件。依賴會(huì)下載到GOPATH/pkg/mod目錄
golist
用GoLand來翻開不同的工程,顯示依賴的外部庫(kù)是不一樣的,如果是用GOPATH創(chuàng)立的工程,需要用命令下載依賴包到GOPATH:
goget-ugithub/fuxing-repo/fuxing-module-name
四
語法
1
包:Package和Import
Java里面的包名一般是很長(zhǎng)的,和文件夾名稱對(duì)應(yīng),作用就是命名空間,引入的時(shí)候需要寫長(zhǎng)長(zhǎng)的一串,也可以用通配符:
Go里面一般的包名是當(dāng)前的文件夾名稱,同一個(gè)工程里面,可以存在同樣的包名,如果同時(shí)都需要引用同樣包名的時(shí)候,就可以用alias辨別,類似于JS那樣。一般import的是一個(gè)包,不像Java那樣import具體的類。同一個(gè)包內(nèi),不同文件,但是里面的東西是可以使用的,不需要import。這有點(diǎn)類似于C的include吧。如果多行的話,用括號(hào)換行包起來。
Go語言中,無論是變量、函數(shù)還是類屬性及辦法,它們的可見性都是與包相關(guān)聯(lián)的,而不是類似Java那樣,類屬性和辦法的可見性封裝在對(duì)應(yīng)的類中,然后通過private、protected和public這些關(guān)鍵字來描述其可見性,Go語言沒有這些關(guān)鍵字,和變量和函數(shù)一樣,對(duì)應(yīng)Go語言的自定義類來說,屬性和辦法的可見性根據(jù)其首字母大小寫來決定,如果屬性名或辦法名首字母大寫,那么可以在其他包中直接訪問這些屬性和辦法,否那么只能在包內(nèi)訪問,所以Go語言中的可見性都是包一級(jí)的,而不是類一級(jí)的。
在Java里面,只有靜態(tài),或者對(duì)象就可以使用點(diǎn)運(yùn)算符,而且是極其常用的操作,而在Go里面,還可以用一個(gè)包名來點(diǎn),這就是結(jié)合了import來使用,可以點(diǎn)出一個(gè)函數(shù)調(diào)用,也可以點(diǎn)出一個(gè)結(jié)構(gòu)體,一個(gè)接口。另外區(qū)別于C,不論是指針地址,還是對(duì)象引用,都是用點(diǎn)運(yùn)算符,不需要考慮用點(diǎn)還是箭頭了!
入口的package必須是main,否那么可以編譯成功,但是跑不起來:
Compiledbinarycannotbeexecuted.
原因就是找不到入口函數(shù),跟C和Java一樣吧,也需要main函數(shù)。
2
變量
用var關(guān)鍵字修飾〔類似于JS〕,有多個(gè)變量的時(shí)候用括號(hào)()包起來,默認(rèn)是有初始化值的,和Java一樣。
如果初始化的時(shí)候就賦值了那可以不需要var來修飾,和Java不同的是變量類型在變量后面而不是前面,不過需要:=符號(hào)。
最大的變化就是類型在變量后面!
語句可以省略分號(hào);
varv1int=10
//方式一,常規(guī)的初始化操作
varv2=10
//方式二,此時(shí)變量類型會(huì)被編譯器自動(dòng)推導(dǎo)出來
v3:=10
//方式三,可以省略var,編譯器可以自動(dòng)推導(dǎo)出v3的類型
//java
privateHashMapmBlockInfo;
多重賦值
i,j=j,i
可以實(shí)現(xiàn)變量交換,有點(diǎn)像JS的對(duì)象析構(gòu),但是其實(shí)不一樣。有了這個(gè)能力,函數(shù)是可以返回多個(gè)值了!
匿名變量
用_來表示,作用就是可以防止創(chuàng)立定義一些無意義的變量,還有就是不會(huì)分配內(nèi)存。
指針變量
和C語言一樣的,回想一下交換值的例子即可,到底傳值和傳址作為參數(shù)的區(qū)別是啥。
Go語言之所以引入指針類型,主要基于兩點(diǎn)考慮,一個(gè)是為程序員提供操作變量對(duì)應(yīng)內(nèi)存數(shù)據(jù)結(jié)構(gòu)的能力;另一個(gè)是為了提高程序的性能〔指針可以直接指向某個(gè)變量值的內(nèi)存地址,可以極大節(jié)省內(nèi)存空間,操作效率也更高〕,這在系統(tǒng)編程、操作系統(tǒng)或者網(wǎng)絡(luò)應(yīng)用中是不容無視的因素。
指針在Go語言中有兩個(gè)使用場(chǎng)景:類型指針和數(shù)組切片。
作為類型指針時(shí),允許對(duì)這個(gè)指針類型的數(shù)據(jù)進(jìn)行修改指向其它內(nèi)存地址,傳遞數(shù)據(jù)時(shí)如果使用指針那么無須拷貝數(shù)據(jù)從而節(jié)省內(nèi)存空間,此外和C語言中的指針不同,Go語言中的類型指針不能進(jìn)行偏移和運(yùn)算,因此更為平安。
變量類型
Go語言內(nèi)置對(duì)下列這些根本數(shù)據(jù)類型的支持:
布爾類型:bool
整型:int8、byte、int16、int、uint、uintptr等
浮點(diǎn)類型:float32、float64
復(fù)數(shù)類型:complex64、complex128
字符串:string
字符類型:rune,本質(zhì)上是uint32
錯(cuò)誤類型:error
此外,Go語言也支持下列這些復(fù)合類型:
指針〔pointer〕
數(shù)組〔array〕
切片〔slice〕
字典〔map〕
通道〔chan〕
結(jié)構(gòu)體〔struct〕
接口〔interface〕
還有const常量,iota這個(gè)預(yù)定義常量用來定義枚舉??梢员徽J(rèn)為是一個(gè)可被編譯器修改的常量,在每一個(gè)const關(guān)鍵字出現(xiàn)時(shí)被重置為0,然后在下一個(gè)const出現(xiàn)之前,每出現(xiàn)一次iota,其所代表的數(shù)字會(huì)自動(dòng)增1。
const(
Sunday=iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays
)
類型強(qiáng)轉(zhuǎn)
v1:=99.99
v2:=int(v1)
//v2=99
v1:=[]byte{'h','e','l','l','o'}
v2:=string(v1)
//v2=hello
//字符相關(guān)的轉(zhuǎn)化一般用strconv包
v1:="100"
v2,err:=strconv.Atoi(v1)
//將字符串轉(zhuǎn)化為整型,v2=100
v3:=100
v4:=strconv.Itoa(v3)
//將整型轉(zhuǎn)化為字符串,v4="100"
//結(jié)構(gòu)體類型轉(zhuǎn)換
//類型斷言
//x.(T)其實(shí)就是判斷T是否實(shí)現(xiàn)了x接口,如果實(shí)現(xiàn)了,就把x接口類型具體化為T類型;
claims,ok:=tokenClaims.Claims.(*jwt.StandardClaims)
數(shù)組與切片
//定義數(shù)組
vara[8]byte//長(zhǎng)度為8的數(shù)組,每個(gè)元素為一個(gè)字節(jié)
varb[3][3]int//二維數(shù)組〔9宮格〕
varc[3][3][3]float64//三維數(shù)組〔立體的9宮格〕
vard=[3]int{1,2,3}
//聲明時(shí)初始化
vare=new([3]string)
//通過new初始化
varf=make([]string,3)//通過make初始化
//初始化
a:=[5]int{1,2,3,4,5}
b:=[...]int{1,2,3}
//切片
b:=[]int{}//數(shù)組切片slice就是一個(gè)可變長(zhǎng)數(shù)組
c:=a[1:3]//有點(diǎn)類似于subString,或者js.slice
d:=make([]int,5)//make相當(dāng)于,new、alloc,用來分配內(nèi)存
//數(shù)組的長(zhǎng)度
length:=len(a)
//添加一個(gè)元素
b=append(b,4)
字典
其實(shí)就是Java里的map,使用上語法有很多不同。
vartestMapmap[string]int
testMap=map[string]int{
"one":1,
"two":2,
"three":3,
}
//還可以這樣初始化:
vartestMap=make(map[string]int)//map[string]int{}
testMap["one"]=1
testMap["two"]=2
testMap["three"]=3
make和new
//Themakebuilt-infunctionallocatesandinitializesanobjectoftype
//slice,map,orchan(only).Likenew,thefirstargumentisatype,nota
//value.Unlikenew,make'sreturntypeisthesameasthetypeofits
//argument,notapointertoit.Thespecificationoftheresultdependson
//thetype:
//
Slice:Thesizespecifiesthelength.Thecapacityofthesliceis
//
equaltoitslength.Asecondintegerargumentmaybeprovidedto
//
specifyadifferentcapacity;itmustbenosmallerthanthe
//
length.Forexample,make([]int,0,10)allocatesanunderlyingarray
//
ofsize10andreturnsasliceoflength0andcapacity10thatis
//
backedbythisunderlyingarray.
//
Map:Anemptymapisallocatedwithenoughspacetoholdthe
//
specifiednumberofelements.Thesizemaybeomitted,inwhichcase
//
asmallstartingsizeisallocated.
//
Channel:Thechannel'sbufferisinitializedwiththespecified
//
buffercapacity.Ifzero,orthesizeisomitted,thechannelis
//
unbuffered.
funcmake(tType,size...IntegerType)Type
//Thenewbuilt-infunctionallocatesmemory.Thefirstargumentisatype,
//notavalue,andthevaluereturnedisapointertoanewly
//allocatedzerovalueofthattype.
funcnew(Type)*Type
區(qū)別就是返回值和參數(shù)不同,一個(gè)是值,一個(gè)是指針,slice、chan、map只能用make,本身就是指針。其他make、new都行。
神奇的nil
Java里面用null比擬舒服,直接就判空了,除了在string類型的時(shí)候,還要判斷字符為"",但是Go里面的string要判斷為空就簡(jiǎn)單一點(diǎn),不能判斷nil,只能判斷""。然而Go里面的nil卻和null不一樣,其實(shí)是和JS里面==、===很像。
nil也是有類型的。
funcFoo()error{
varerr*os.PathError=nil
//…
returnerr
//實(shí)際返回的是[nil,*os.PathError]
//returnnil//正確的方式是直接returnnil
實(shí)際返回的是[nil,nil]
}
funcmain(){
err:=Foo()
fmt.Println(err)
//
fmt.Println(err==nil)//false
fmt.Println(err==(*os.PathError)(nil))//true
}
根對(duì)象:Object
在Java里面,如果不用多態(tài),沒有接口,父類,超類的話,就用Object作為根對(duì)象,在Go里面,如果函數(shù)參數(shù)不知道用什么類型,通常會(huì)用interface{},這是個(gè)空接口,表示任意類型,因?yàn)椴皇侨躅愋驼Z言,沒有any類型,也不是強(qiáng)面向?qū)ο笳Z言,沒有Object,所以就有這個(gè)空接口的出現(xiàn)。
3
語句
比擬大的一個(gè)特點(diǎn)就是能不用括號(hào)的地方都不用了。
控制流程
if語句的判斷條件都沒有了括號(hào)包起來,還可以前置寫變量初始化語句,類似于for循環(huán),左花括號(hào){必須與if或者else處于同一行。
switch語句變得更強(qiáng)大了,有這些變化:
switch關(guān)鍵字后面可以不跟變量,這樣case后面就必須跟條件敘述式,其實(shí)本質(zhì)上就是美化了if-else-if。
如果switch后面跟變量,case也變得強(qiáng)大了,可以出現(xiàn)多個(gè)結(jié)果選項(xiàng),通過逗號(hào)分隔。
swtich后面還可以跟一個(gè)函數(shù)。
不需要用break來明確退出一個(gè)case,如果要穿透執(zhí)行一層,可以用fallthrough關(guān)鍵字。
score:=100
switchscore{
case90,100:
fmt.Println("Grade:A")
case80:
fmt.Println("Grade:B")
case70:
fmt.Println("Grade:C")
case60:
case65:
fmt.Println("Grade:D")
default:
fmt.Println("Grade:F")
}
s:="hello"
switch{
cases=="hello":
fmt.Println("hello")
fallthrough
cases=="xxxx":
fmt.Println("xxxx")
cases!="world":
fmt.Println("world")
}
//output:helloxxxx
循環(huán)流程
去掉了while、repeat這些關(guān)鍵字了,只保存了for這個(gè)關(guān)鍵字,其實(shí)用起來差不多。break,continue這些關(guān)鍵字還是有的。
//通用的用法
fori:=1;i
fmt.Println(i)
}
//類似于while的用法
a:=1
fora
fmt.Println(a)
a++
}
//死循環(huán)
for{
//dosomething
}
for;;{
//dosomething
}
//類似javafor-each的用法
listArray:=[...]string{"xiaobi","xiaoda","xiaoji"}
forindex,item:=rangelistArray{
fmt.Printf("hello,%d,%s\n",index,item)
}
//java
for(Stringitem:someList){
System.out.println(item);
}
跳轉(zhuǎn)流程
Go很神奇的保存了一直被放棄的goto語句,記得是Basic、Pascal那些語言才會(huì)有,不知道為啥。
i:=1
flag:
fori
ifi%2==1{
i++
gotoflag
}
fmt.Println(i)
i++
}
defer流程有點(diǎn)像Java里面的finally,保證了一定能執(zhí)行,我感覺底層也是goto的實(shí)現(xiàn)吧。在后面跟一個(gè)函數(shù)的調(diào)用,就能實(shí)現(xiàn)將這個(gè)xxx函數(shù)的調(diào)用延遲到當(dāng)前函數(shù)執(zhí)行完后再執(zhí)行。
這是壓棧的變量快照實(shí)現(xiàn)。
funcprintName(namestring){
fmt.Println(name)
}
funcmain(){
name:="go"
deferprintName(name)//output:go
name="python"
deferprintName(name)//output:python
name="java"
printName(name)//output:java
}
//output:
java
python
go
//defer后于return執(zhí)行
varnamestring="go"
funcmyfunc()string{
deferfunc(){
name="python"
}()
fmt.Printf("myfunc函數(shù)里的name:%s\n",name)
returnname
}
funcmain(){
myname:=myfunc()
fmt.Printf("main函數(shù)里的name:%s\n",name)
fmt.Println("main函數(shù)里的myname:",myname)
}
//output:
myfunc函數(shù)里的name:go
main函數(shù)里的name:python
main函數(shù)里的myname:
go
4
函數(shù)
關(guān)鍵字是func,Java那么完全沒有function關(guān)鍵字,而是用public、void等等這樣的關(guān)鍵字,JS也可以用箭頭函數(shù)來去掉function關(guān)鍵字了。
函數(shù)的花括號(hào)強(qiáng)制要求在首行的末尾。
可以返回多個(gè)值!返回值的類型定義在參數(shù)后面了,而不是一開始定義函數(shù)就需要寫上,跟定義變量一樣,參數(shù)的類型定義也是一樣在后面的,如果相同那么保存最右邊的類型,其他省略。
可以顯式聲明了返回值就可以了,必須每個(gè)返回值都顯式,就可以省略return變量。
//一個(gè)返回值
funcGetEventHandleMsg(codeint)string{
msg,ok:=EventHandleMsgMaps[code]
ifok{
returnmsg
}
return""
}
//多個(gè)返回值
funcGetEventHandleMsg(codeint)(string,error){
msg,ok:=EventHandleMsgMaps[code]
ifok{
returnmsg,nil
}
return"",nil
}
//不顯式return變量值
funcGetEventHandleMsg(codeint)(msgstring,eerror){
varokbool
msg,ok=EventHandleMsgMaps[code]
ifok{
//dosomething
return
}
return
}
匿名函數(shù)和閉包
在Java里面的實(shí)現(xiàn)一般是內(nèi)部類、匿名對(duì)象,不能通過辦法傳遞函數(shù)作為參數(shù),只能傳一個(gè)對(duì)象,實(shí)現(xiàn)接口。
Go那么和JS一樣方便,可以傳遞函數(shù),定義匿名函數(shù)。
//傳遞匿名函數(shù)
funcmain(){
i:=10
add:=func(a,bint){
fmt.Printf("Variableifrommainfunc:%d\n",i)
fmt.Printf("Thesumof%dand%dis:%d\n",a,b,a+b)
}
callback(1,add);
}
funccallback(xint,ffunc(int,int)){
f(x,2)
}
//return匿名函數(shù)
funcmain(){
f:=addfunc(1)
fmt.Println(f(2))
}
funcaddfunc(aint)func(bint)int{
returnfunc(bint)int{
returna+b
}
}
不定參數(shù)
和Java類似,不同的是在調(diào)用是也需要用...來標(biāo)識(shí)。
//定義
funcSkipHandler(c*gin.Context,skippers...SkipperFunc)bool{
for_,skipper:=rangeskippers{
ifskipper(c){
returntrue
}
}
returnfalse
}
//調(diào)用
middlewares.SkipHandler(c,skippers...)
五
面向?qū)ο?/p>
在C語言里面經(jīng)常會(huì)有用到別名的用法,可以用type類起一個(gè)別名,很常用,特別是在看源碼的時(shí)候經(jīng)常出現(xiàn):
typeIntegerint
1
類
沒有class的定義,Go里面的類是用結(jié)構(gòu)體來定義的。
typeStudentstruct{
iduint
namestring
malebool
scorefloat64
}
//沒有構(gòu)造函數(shù),但是可以用函數(shù)來創(chuàng)立實(shí)例對(duì)象,并且可以指定字段初始化,類似于Java里面的靜態(tài)工廠辦法
funcNewStudent(iduint,namestring,malebool,scorefloat64)*Student{
return&Student{id,name,male,score}
}
funcNewStudent2(iduint,namestring,malebool,scorefloat64)Student{
returnStudent{id,name,male,score}
}
2
成員辦法
定義類的成員函數(shù)辦法比擬隱式,方向是反的,不是聲明這個(gè)類有哪些成員辦法,而是聲明這個(gè)函數(shù)是屬于哪個(gè)類的。聲明語法就是在func關(guān)鍵字之后,函數(shù)名之前,注意不要把Java的返回值定義給混同了!
//這種聲明方式和C++一樣的,這個(gè)就是不是普通函數(shù)了,而是成員函數(shù)。
//注意到的是,兩個(gè)辦法一個(gè)聲明的是地址,一個(gè)聲明的是結(jié)構(gòu)體,兩個(gè)都能直接通過點(diǎn)操作。
func(sStudent)GetName()string
{
return
}
func(s*Student)SetName(namestring){
=name
}
//使用
funcmain(){
//a是指針類型
a:=NewStudent(1,"aa",false,45)
a.SetName("aaa")
fmt.Printf("aname:%s\n",a.GetName())
b:=NewStudent2(2,"bb",false,55)
b.SetName("bbb")
fmt.Printf("bname:%s\n",b.GetName())
}
//如果SetName辦法和GetName辦法歸屬于Student,而不是*Student的話,則修改名字就會(huì)不成功
//本質(zhì)上,聲明成員函數(shù),就是在非函數(shù)參數(shù)的地方來傳遞對(duì)象、指針、或者說是引用,也就是變相傳遞this指針
//所以才會(huì)出現(xiàn)修改名字不成功的case
3
繼承
沒有extend關(guān)鍵字,也就沒有了繼承,只能通過組合的方式來實(shí)現(xiàn)。組合就解決了多繼承問題,而且多繼承的順序不同,內(nèi)存結(jié)構(gòu)也不同。
typeAnimalstruct{
namestring
}
func(aAnimal)FavorFood()string{
return"FavorFood..."
}
func(aAnimal)Call()string{
return"Voice..."
}
typeDogstruct{
Animal
}
func(dDog)Call()string{
return"汪汪汪"
}
//第二種方式,在初始化就需要指定地址,其他都沒變化
typeDog2struct{
*Animal
}
functest(){
d1:=Dog{}
="mydog"
d2:=Dog2{}
="mydog2"
//結(jié)構(gòu)體是值類型,如果傳入值變量的話,實(shí)際上傳入的是結(jié)構(gòu)體值的副本,對(duì)內(nèi)存消耗更大,
//所以傳入指針性能更好
a:=Animal{"ddog"}
d3:=Dog{a}
d4:=Dog2{&a}
}
這種語法并不是像Java里面的組合,使用成員變量,而是直接引用Animal并沒有定義變量名稱〔當(dāng)然也是可以的,不過沒必要了〕,然后就可以訪問Animal中的所有屬性和辦法〔如果兩個(gè)類不在同一個(gè)包中,只能訪問父類中首
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 電信服務(wù)大院租賃合同
- 船舶制造企業(yè)財(cái)務(wù)主管招聘合同
- 國(guó)企薪酬管理案例分析
- 按摩保健入駐管理
- 藝術(shù)表演主持人招聘協(xié)議
- 國(guó)際援助愛心基金管理辦法
- 商業(yè)慶典演員招募協(xié)議
- 市政工程項(xiàng)目招投標(biāo)要點(diǎn)
- 學(xué)校采暖設(shè)備安裝協(xié)議
- 員工宿舍住宿人員宿舍垃圾分類
- GB/T 17892-2024優(yōu)質(zhì)小麥
- 調(diào)酒初級(jí)基礎(chǔ)理論知識(shí)單選題100道及答案解析
- 第5課用發(fā)展的觀點(diǎn)看問題2023-2024學(xué)年中職高教版2023哲學(xué)與人生
- 危廢治理項(xiàng)目經(jīng)驗(yàn)-危廢治理案例分析
- 南京市2024-2025學(xué)年六年級(jí)上學(xué)期11月期中調(diào)研數(shù)學(xué)試卷二(有答案)
- 2021大學(xué)生個(gè)人職業(yè)生涯規(guī)劃書6篇
- 汽車防凍液中毒
- 粉條產(chǎn)品購(gòu)銷合同模板
- 2024至2030年中國(guó)自動(dòng)車配件行業(yè)投資前景及策略咨詢研究報(bào)告
- 2024-2030年中國(guó)蔗糖行業(yè)市場(chǎng)深度調(diào)研及發(fā)展趨勢(shì)與投資前景研究報(bào)告
- 北師版 七上 數(shù)學(xué) 第四章 基本平面圖形《角-第2課時(shí) 角的大小比較》課件
評(píng)論
0/150
提交評(píng)論