摘要:小白前端一枚,最近在研究,記錄自己學習過程中的一些筆記,以及自己的理解。此外,結(jié)構(gòu)體也支持嵌套。在函數(shù)聲明時,在函數(shù)名前放上一個變量,這個變量稱為方法的接收器,一般是結(jié)構(gòu)體類型的。
小白前端一枚,最近在研究golang,記錄自己學習過程中的一些筆記,以及自己的理解。
go中包的依賴管理
go中的切片
byte 和 string
go中的Map
go中的struct結(jié)構(gòu)體
go中的方法
go中的interface接口
interface{}
原文在我的博客中:https://github.com/forthealll...
歡迎star~
1、go中包的依賴管理首先要了解的是GOPATH的含義,GOPATH是go命令依賴的重要變量,可以通過:
go env
來查看相應(yīng)的開發(fā)環(huán)境中GOPATH的值,也可以通過export GOPATH指定:
export GOPATH = /usr/local/go
指定GOPATH目錄后, GOPATH目錄包含了3個子目錄:
src存放源代碼(比如.go、.h文件等)
pkg編譯時生成的中間文件
bin編譯后生成的可執(zhí)行文件
此外,go的依賴管理中提供了3個主要的命令go build、go get和 go install。
go build: 會編譯目錄下或者指定的.go文件,得到一個可執(zhí)行的文件
go install: 只能在GOPATH目錄下使用,與go build大致相同會編譯目錄下執(zhí)行的.go文件,此外go install還會將可執(zhí)行文件或庫文件安裝到GOPATH目錄下。
go install + 遠程地址: 會將相應(yīng)的代碼下載到GOPATH同時會編譯該遠程包
go get + 遠程地址: 跟go install+遠程地址相同,會下載且編譯
go get u + 遠程地址: 下載并更新相應(yīng)的遠程地址的包,但不會自動編譯
典型的例子,比如下載一個dep包:
go get -u github.com/golang/dep/cmd/dep
上述的go get和go install + 遠程包的方式,不能應(yīng)用于需要版本管理依賴等場景,可以通過安裝dep包,來實現(xiàn)依賴管理。dep提供了幾個常用的命令,分別用于安裝和更新相應(yīng)的go包。
dep init 初始化一個項目依賴
dep ensure 安裝項目所依賴的所有包
dep ensure -update 更新項目中的所有包
dep ensure -add github.com/pkg/errors 為項目添加單個依賴包
此外通過Gopkg.toml里面可以指定所依賴包的git分支,版本號等等,且在dep ensure -add中也可以指定分支和版本號,比如:
dep ensure -add github.com/pkg/foo@^1.0.1
提到包(package),必須補充一句,在go中如果在其他包中引用變量,是通過:
包名.變量名
的形式,在這里變量名必須是大寫的,也就是說在go的包中,變量能否導(dǎo)出是根據(jù)變量的大小寫來確定的,普遍認為如果變量是大寫的就是在包內(nèi)導(dǎo)出的,如果是變量小寫的就是默認是包的私有變量。
2、go中的切片在go的函數(shù)調(diào)用中,如果傳遞的參數(shù)是一個較大的數(shù)組,顯然如果直接將數(shù)組作為實參傳入,在執(zhí)行函數(shù)的過程中,實際上會拷貝一份該數(shù)組,會造成內(nèi)存的浪費等。標準的做法,是傳入數(shù)組的指針,或者對于數(shù)組的部分引用。
這里關(guān)于數(shù)組的部分引用,就是slice切片
(1)、go中的切片簡介數(shù)組和切片之間存在著緊密的聯(lián)系,slice提供了訪問數(shù)組子序列的功能。所謂的切片是對于數(shù)組的部分引用,slice由三部分組成指針、長度和容量。
指針: 指向第一個slice元素所對應(yīng)的數(shù)組元素的地址
長度: slice中元素的數(shù)目
容量: slice中最多可容納元素的數(shù)目
切片的定義方式:
var slice1 []type = make([]type, len, cap)
分別指定切片的類型,長度以及容量。
切片的初始化:
s := [] int { 1,2,3 }
或者通過已經(jīng)存在的數(shù)組來實現(xiàn)切片的初始化,
arr = [10]int {1,2,3,4,5,6,7,8,9,10} s:=arr[1:5] // arr[startIndex:endIndex](2)、go中的切片注意點
go中的slice切片有一個注意點,就是如何判斷切片為空,邊界情況大致如下所示:
var s []int //len(s)==0,s==nil s = nil //len(s)==0,s==nil s = []int(nil)//len(s)==0,s==nil s = []int{} //len(s)==0,s!=nil
顯然如果通過s==nil來判斷,不能區(qū)別第四種場景,因此判斷切片為空的正確方式是len(s)==0.
3、byte 和 string下述的方法將返回一個byte的切片:
var test:= []byte("hello")
go遍歷slice動態(tài)刪除 map遍歷刪除安全.
4、go中的Mapmap是一個無序的key/value對的集合,其中在每一個map中key是唯一的。go中的map只要坑在于map是無序的。
(1)、Map簡介聲明一個map:
var ages map[string]int //同樣初始的情況下,ages = nil ages == nil // true
如果聲明了但是沒有賦值,那么嘗試插入一對key/value會報錯,比如上述聲明但沒有初始化的情況下:
age["jony"] = 25 // 會panic
解決方法,就是給age定義后賦值:
ages = make(map[string]int)
或者定義的時候同時賦值:
ages := map[string]int{ }
此后插入不存在的key/value就不會報錯。
注意:嘗試從map中去一個不存在的key,默認的value值為0
(2)、Map無序性我們從map的遍歷結(jié)果,來說明map是無序的。比如我們以這么一個map為例:
var ages = map[string]int{ "a":21, "b":22, "c":23, }; for name,age := range ages { fmt.Printf("%s %d ",name,age); }
通過for range可以遍歷map對象,分別執(zhí)行三次遍歷后,來看遍歷的結(jié)果
第一次輸出:
c 23
a 21
b 22
第二次輸出:
c 23
b 22
a 21
第三次輸出:
a 21
b 22
c 23
從上述的結(jié)果我們也可以看出map的每次遍歷的結(jié)果都是不確定的。
注意:Map的value類型不僅僅可以是基本類型,也可以是聚合類型,比如map或者slice。
5 、go中的struct結(jié)構(gòu)體跟C++中的結(jié)構(gòu)體類似,go中的結(jié)構(gòu)體是一種聚合數(shù)據(jù)類型,由0個或者多個任意值聚合成實體。
(1)、結(jié)構(gòu)體簡介聲明一個結(jié)構(gòu)體很簡單,比如我們聲明了一個Person結(jié)構(gòu)體:
type Person struct { name string age int salary int }
然后可以聲明一個Person類型的變量:
var person Person
然后可以通過點操作符訪問和賦值。
person.age = 25
此外,可以通過取地址符號加點操作符來訪問和賦值,下述取地址的方式效果與上述是相同的。
(&person).age = 25
此外,結(jié)構(gòu)體也支持嵌套。
6、go中的方法在go中沒有明確的定義類,但是可以將結(jié)構(gòu)體struct來類比其他語言中的class。
go中的方法與結(jié)構(gòu)體相關(guān),為了說名go中的方法,我們先從go中的函數(shù)講起。
(1)、go中的函數(shù)簡介在go中函數(shù)聲明包括函數(shù)名、形參列表、返回值列表(可省略 不傲視無返回值)以及函數(shù)體。
func name (parameter-list)(result-list){ }
比如我們有一個count函數(shù)可以如此簡單的定義:
func count(x,y int) int { return x + y }(2)、go中方法簡介
在函數(shù)定義的基礎(chǔ)上我們來介紹一下,如何定義方法。在函數(shù)聲明時,在函數(shù)名前放上一個變量,這個變量稱為方法的接收器,一般是結(jié)構(gòu)體類型的。
當然也不一定是結(jié)構(gòu)體,基本類型數(shù)值、字符串、slice和map上面都可以作為接收器來定義方法。
聲明方法的方式具體可以如下所示:
func (receive Receive) name(parameter-list)(result-list){ }
從上述的聲明中也可以看出來只不過在函數(shù)的技術(shù)上增加了第一個參數(shù)接收器,為相應(yīng)的接收器增加了該名稱的方法。比如我們定一個Person結(jié)構(gòu)體,并為其聲明sellHello方法:
type Person struct { name string age int salary int } func (person Person) sayHello() string{ return "Hello "+ person.name } p := Person{ name: "Jony", age: 25, salary:100 } fmt.Println(p.sayHello());//輸出Hello Jony
上述就是在結(jié)構(gòu)體Person上定義了一個sayHello方法,在結(jié)構(gòu)體被初始化后,可以通過p.sayHello()的方式直接調(diào)用。
除此之外,我們前面將到定義方法時的接收器不一定是一個結(jié)構(gòu)體,接收器也可以接受基本類型等,比如:
type Mystring string; func (mystring Mystring)sayHello() string{ return "Hello"+ string(mystring); } var m Mystring m = "Jony" fmt.Println(m.sayHello());
上述的例子同樣會輸出Hello Jony.
甚至nil也可以作為方法的接收器,這里就不具體舉例。
(3)、基于指針對象的方法在函數(shù)調(diào)用時,是對實參的一個拷貝,如果函數(shù)需要更新一個變量,或者傳遞的參數(shù)過大,默認拷貝太為負責,我們經(jīng)常會使用指針的形式,對于方法而言也同樣如此,也就是說方法的接收器可以是指針類型。
對比于上述非指針類型的方法,聲明指針類型的方法具體如下所示:
func (receive *Receive) name(parameter-list)(result-list){ }
指針類型的參數(shù)作為接收器,可以修改傳入?yún)?shù)的實際變量的值。
type Person struct { name string age int salary int } func (person *Person) changeAge(newAge int){ (*person).age = newAge } p.changeAge(30); fmt.Println(p.age); //輸出了30,發(fā)現(xiàn)age確實發(fā)生了改變。7、go中的interface接口
我們前面也說過go不是一種傳統(tǒng)的面向?qū)ο蟮恼Z言,沒有類和繼承的概念,go里面通過interface接口可以實現(xiàn)很多面向?qū)ο蟮奶匦浴?/p>
接口的通俗定義:
接口提供了一種方式來說明對象的行為,接口定義了一組方法,但是不包含實現(xiàn)。
(1)、interface接口簡介可以通過如下格式來定義接口:
type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ... }
go中的接口都很簡短,一般包含了0-3個方法。
同時我們可以通過:
var ai Namer
來定義一個接口類型的變量,初始值為nil.接口類型的變量是一個指針,聲明而未賦值的情況下就為nil。
go中的接口有以下需要注意的點:
一個類型可以實現(xiàn)多個接口
接口類型可以包含一個實例的引用,該實例的類型實現(xiàn)了此接口
即使接口在類型之后定義,二者存在不同的包中,被多帶帶編譯,但是只要類型實現(xiàn)了接口中的方法,它就實現(xiàn)了此接口
實現(xiàn)某個接口的類型,除了實現(xiàn)接口方法外,還可以有其他的方法
上述幾點都比較好理解,具體第二點,舉例來說:
type Person struct { name string age int salary int } type Say interface { sayHello() string } func (person Person) sayHello() string { return "Hello "+person.name } func main() { p := new(Person) p.name = "Jony" var s Say; s = p; fmt.Println(s) }
上述例子中,我們首先new了一個Person結(jié)構(gòu)體類型的變量,并賦值給p,因為Person接口體中實現(xiàn)了Say接口中的所有方法sayHello等。因此我們就說Person實現(xiàn)了Say接口,因此Person的實例p,可以賦值給一個Say接口類型的變量s。
此時的s是個指針,指向Person結(jié)構(gòu)體實例p。
(2)、interface接口類型斷言任何類型只要實現(xiàn)了接口中的所有方法,我們就說該類型實現(xiàn)了該接口。這樣一個接口類型的變量varI可以包含任何類型的值,在go中提供了一種安全的方式來檢測它的動態(tài)類型。
if v,ok := varI.(T);ok { Process(v) return }
如果轉(zhuǎn)化合法,那么v是varI轉(zhuǎn)化到類型T的值,ok會是true,否則v是類型T的零值,ok是false。這是一種安全的轉(zhuǎn)化方式不會有錯誤發(fā)生。
我們還是接著上面的代碼來講我們的例子:
type Person struct { name string age int salary int } type Say interface { sayHello() string } func (person Person) sayHello() string { return "Hello "+person.name } func main() { p := new(Person) p.name = "Jony" var s Say; s = p; if t,ok := s.(*Person);ok { fmt.Printf("The type of s is:%T ",t); } }
輸出的結(jié)果為The type of s is:*main.Person。也可以使用特殊的type-switch來判斷。
switch t:= s.(*Person){ case *Person: fmt.Printf("The type of s is:%T ",t); case nil: ... default: ... }8、interface{}
interface{}是一個空接口,任何類型的值都可以復(fù)制給interface{}類型的變量。
比如,我們首先聲明一個類型為interface{}的變量:
var test interface{}
任意類型的值都可以復(fù)制給test,比如下列基本類型的值復(fù)制給test是有效的:
var test interface{} test = 1 test = true test ="Hello"
此外,復(fù)雜的派生類型也可以賦值給test,我們以指針類型舉例:
var test interface{} var a = 1 test = &a
interface類型的變量是沒有類型的,但是我們可以人為的進行類型轉(zhuǎn)換:
var test interface{} var a string test = "hello" a = test.(string)
上述,可以將test轉(zhuǎn)化成string類型,這樣就可以賦值給string類型變量a了。通過.(類型名)的方法可以將interface{}類型的變量轉(zhuǎn)化成任意的類型。
最后舉一個簡單的例子:
func main() { a := make([]interface{},10) b :=1 a[1]=&b fmt.Println(*(a[1].(*int))) }
上述代碼發(fā)現(xiàn),將interface{}類型切片中的某一元素的值復(fù)制給了int指針類型,然后進行了類型轉(zhuǎn)化,將interface{}類型的變量轉(zhuǎn)換成了int指針類型。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108853.html
摘要:中的設(shè)計非常輕量,又兼具很高的擴展性,初學者都可以輕易的設(shè)計出自定義的路由功能,使用上十分簡單這里來吐槽一下的,雖然我也對愛得深沉,下面請看的。一般網(wǎng)站的路由規(guī)則太多了,編寫繁瑣,可以通過的方法進行一種簡化。????由于本人之前一直是Java Coder,在Java web開發(fā)中其實大家都很依賴框架,所以當在學習Golang的時候,自己便想著在Go開發(fā)中脫離框架,自己動手造框架來練習。通過學...
摘要:中的設(shè)計非常輕量,又兼具很高的擴展性,初學者都可以輕易的設(shè)計出自定義的路由功能,使用上十分簡單這里來吐槽一下的,雖然我也對愛得深沉,下面請看的。一般網(wǎng)站的路由規(guī)則太多了,編寫繁瑣,可以通過的方法進行一種簡化。????由于本人之前一直是Java Coder,在Java web開發(fā)中其實大家都很依賴框架,所以當在學習Golang的時候,自己便想著在Go開發(fā)中脫離框架,自己動手造框架來練習。通過學...
閱讀 1698·2021-10-28 09:32
閱讀 605·2021-09-24 09:47
閱讀 2920·2021-09-02 15:11
閱讀 2731·2021-08-09 13:46
閱讀 2884·2019-08-30 15:55
閱讀 1071·2019-08-30 15:54
閱讀 3299·2019-08-29 14:12
閱讀 805·2019-08-26 13:40