go入門(二)

本文以面向?qū)ο鬄榛A(chǔ)搬男,闡述一下go中的某些功能的使用拣展。

高級(jí)數(shù)據(jù)類型

高級(jí)數(shù)據(jù)的關(guān)鍵字是type。下面簡(jiǎn)單描述每種對(duì)象的聲明:

數(shù)組

數(shù)據(jù)必須定義類型缔逛,所有元素都有默認(rèn)值备埃。

    //第一種  先定義姓惑,而后賦值  []中的長(zhǎng)度不可以省略,運(yùn)行會(huì)出錯(cuò)
    var arr [2]int
    arr01 := []int{}
    arr[0] = 2
    //第二種
    arr1 := [3]int{1, 2, 3}
    //第三種  此處的[]中可以寫長(zhǎng)度值按脚,也可以不寫于毙,也可以寫...
    //因?yàn)楹竺娴膡}里有值,go會(huì)自動(dòng)計(jì)算出該數(shù)組的長(zhǎng)度
    arr2 := []int{4, 5, 6}
    arr21 := [...]int{4, 5, 6}
    //第四種 不按順序來編寫數(shù)組的值辅搬,而是按照索引
    //下面數(shù)據(jù)的輸出是[3 1]
    //索引1位置的是1唯沮,索引0位置的是3
    arr3 := []int{1: 1, 0: 3}
    fmt.Println(arr, arr01, arr1, arr2, arr21, arr3)

基本方法:

  • len():求數(shù)組長(zhǎng)度,如len(arr21)堪遂。
  • cap():求數(shù)組容量介蛉,如cap(arr21)。
  • append():給數(shù)組追加元素(不會(huì)覆蓋默認(rèn)值)溶褪。arr21=append(arr21,22,23)币旧,值為[5 6 22 23]

Tips:關(guān)于len()和cap()的區(qū)別
在數(shù)組中,這兩個(gè)是一樣的猿妈。
在切片中吹菱,cap()是總?cè)萘浚琹en()是可見元素的長(zhǎng)度彭则。所以cap()>=len()鳍刷。

切片

切片,數(shù)組的一種贰剥,類似于java中的數(shù)組截?cái)嗲憬恕5莏ava中的截?cái)嗍巧梢粋€(gè)新數(shù)組筷频,這個(gè)是返回指定索引蚌成,還有可能通過切片擴(kuò)容訪問原數(shù)組。
數(shù)組中的所有方法都可以給切片使用凛捏。

    var numbers4 = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    slice5 := numbers4[4:6:8]
    fmt.Println(len(slice5), cap(slice5))
    fmt.Println("slice5-1:", slice5)
    slice5 = slice5[:cap(slice5)]
    fmt.Println("slice5-2:", slice5)
    slice5 = append(slice5, 11, 12, 13)
    fmt.Println("slice5-3:", slice5)

如下是輸出內(nèi)容:

2 4
slice5-1: [5 6]
slice5-2: [5 6 7 8]
slice5-3: [5 6 7 8 11 12 13]

關(guān)于切片的使用担忧,有一種比numbers4[4:6:8]簡(jiǎn)單的用法,numbers4[4:6]坯癣。不同的是前者擴(kuò)容瓶盛,會(huì)找原數(shù)組下標(biāo)為8的元素,并將原數(shù)組下標(biāo)48的元素返回示罗,而后者一直都是原數(shù)組下標(biāo)46的元素惩猫。

字典

類似于在java中的map。其關(guān)鍵字也是map蚜点。
示例如下:

    //定義一個(gè)string類型的鍵轧房,int類型值的字典(不初始化則{}內(nèi)為空即可)
    enums := map[string]int{"Z": 100, "W": 44}
    //給enum添加鍵值對(duì),鍵為“X”绍绘,值為99
    enums["X"] = 99
    //獲取鍵為“Z”的值
    i := enums["Z"]
    fmt.Println(enums, i)
    //獲取鍵為“X”的值奶镶,如果沒有迟赃,返回該類型的默認(rèn)值
    //如果沒有,則此時(shí)ok為false
    p, ok := enums["X"]
    fmt.Println(enums, p, ok)
    //刪除鍵值為“Z”的鍵值對(duì)
    delete(enums, "Z")
    fmt.Println(enums)

輸出結(jié)果:

map[W:44 X:99 Z:100] 100
map[W:44 X:99 Z:100] 99 true
map[W:44 X:99]

關(guān)于p, ok := enums["X"]這種寫法厂镇,以后會(huì)很常見這種寫法纤壁。因?yàn)閷?duì)獲取的元素是否存在的不確定性,所以ok變量是表示該元素是否存在的bool值捺信。

通道

通道類型為chan酌媒,用符號(hào)<-來表示。其數(shù)據(jù)格式類似于隊(duì)列迄靠。示例如下:

    //表示簡(jiǎn)歷4個(gè)長(zhǎng)度的通道
    ints := make(chan int, 4)
    ints <- 1
    ints <- 2

    i := <-ints            //此處是1
    ints <- 4
    ints <- 7
    ints <- 71
    <-ints                 //此處是2
    fmt.Println(i, <-ints) //此處是4

關(guān)于上面的通道ints馍佑,直接輸出ints位地址,而<-ints表示ints中存儲(chǔ)的值梨水。而<-ints也可以和別的變量進(jìn)行運(yùn)算拭荤。
i:=<-ints這一行,會(huì)彈出一個(gè)長(zhǎng)度的數(shù)據(jù)疫诽。當(dāng)塞入的長(zhǎng)度超出指定的長(zhǎng)度時(shí)舅世,會(huì)拋出錯(cuò)誤。相當(dāng)于隊(duì)列滿了奇徒,不能再塞入了雏亚。

fatal error: all goroutines are asleep - deadlock!

goroutines是go的函數(shù)模型,可以理解為一次性輕量級(jí)線程摩钙。在不使用協(xié)程時(shí)罢低,主函數(shù)運(yùn)行完了,此時(shí)沒有其他函數(shù)去執(zhí)行管道設(shè)值胖笛,程序就放棄等待了网持,然后出錯(cuò)了。

針對(duì)于上面的情況长踊,

    i1 := 1
    //定義int型通道c1功舀,默認(rèn)長(zhǎng)度為0
    c1 := make(chan int)

    go func() {
        c1 <- 11
    }()

    fmt.Println("第一次:", i1)
   //c1中的值賦值給i1
    i1 = <-c1
    fmt.Println("第二次:", i1)

輸出的結(jié)果:
第一次: 1
第二次: 11

因?yàn)槟J(rèn)的通道為非緩沖通道,其長(zhǎng)度為0身弊,所以此時(shí)需要借助協(xié)程來操作辟汰。而第一個(gè)例子的通道指定了長(zhǎng)度,叫做緩沖通道阱佛。
go fun(){}表示一個(gè)協(xié)程來運(yùn)行其所包含的代碼帖汞。

協(xié)程

理解協(xié)程,要和多線程進(jìn)行比較凑术。二者的共同點(diǎn)就是并發(fā)翩蘸,但是協(xié)程是線程自己內(nèi)部進(jìn)行切換,由程序決定麦萤,而多線程是多個(gè)線程間切換鹿鳖,有切換上下文開銷扁眯。相比較而言,協(xié)程開銷小的多翅帜。

函數(shù)

在go中方法首字母大寫等于public(公開)姻檀,小寫等于protect(同包)。沒有其他訪問范圍限制涝滴。

對(duì)于JS中函數(shù)熟悉的人绣版,對(duì)go中的函數(shù)理解也會(huì)很快的。
函數(shù)的基本形式為:

//第一種形式
func sum(a int, b int) int {
    return a+b
}
//第二種形式
func sum1(a int,b int)(c int)  {
     c=a+b
     return
}

對(duì)于函數(shù)歼疮,入?yún)樽兞棵?變量類型杂抽。輸出類型在最后。void類型的不寫韩脏。如果入?yún)⒌念愋筒糠窒嗤豸铮瑒t可以sum(a, b int)這樣寫法。在go中赡矢,所有方法不管出入?yún)?shù)類型是否相同杭朱,方法名必須不同!

在JS中吹散,函數(shù)可以用匿名變量代替弧械,針對(duì)于上面的sum函數(shù):

   //第一種
    var s0 = sum
    s0(1, 2)
   //第二種
    var s1 = func(a, b int) int {
        return a + b
    }
    s1(2, 3)

對(duì)于匿名函數(shù),還有一種是在第二種后面直接加()空民,寫上入?yún)⑷刑疲@種是一次性的,個(gè)人感覺有點(diǎn)類似于閉包界轩。復(fù)用性不大画饥,有興趣的可以自己嘗試。

go中的函數(shù)支持返回多個(gè)值耸棒,如下示例:

func sum2(a, b int) (int, bool) {
    return a + b, true
}

結(jié)構(gòu)體

go中的結(jié)構(gòu)體類似于就java中的類荒澡。他可以封裝屬性报辱、函數(shù)等与殃。
示例,演示go中的繼承:

type Animal struct {
    name string
    Age  int
}

type Dog struct {
    //繼承部分
    Animal
    color string
    name string
}

func main() {
    animal := Animal{"hh", 33}
    
    var dog Dog
    dog.Animal.name="XX1"
    dog.name="XX2"

    fmt.Println(animal, dog)
}

輸出如下:
{hh 33} {{XX1 0} XX2}

值得一提的是碍现,在Dog類中幅疼,如果沒有name屬性,那么調(diào)用dog.name屬性會(huì)直接指向dog.Animal.name屬性昼接。

匿名結(jié)構(gòu)體

    dog := struct {
        name  string
        age   int
        color string
    }{"小黃", 5, "#FF0000"}

    fmt.Println(dog)

方法體
方法體爽篷,即屬于某一結(jié)構(gòu)專屬的方法調(diào)用。
方法體是一種特殊的函數(shù)慢睡。所以上面函數(shù)部分的規(guī)則也同樣適用于方法體逐工。

func (animal *Animal) GrowUp() {
    animal.Age++
}

接口

一個(gè)接口代表著某一種類型的行為铡溪。
接口的基本定義格式如下:

type Animal interface {
    Grow()
    Move(string) string
}

可以發(fā)現(xiàn),接口內(nèi)方法的定義和java是有相似之處的——都只有方法聲明泪喊,沒有方法體棕硫。在go的接口中,不支持屬性袒啼。

接口的類型轉(zhuǎn)換

func main() {
    d := Dog{"Robert", 3, "Beijing"}
    v := interface{}(&d)
    animal := v.(Animal)
    fmt.Println(animal)
}
type Animal interface {
    Grow()
    Move(string) string
}

type Dog struct {
    name    string
    Age     int
    address string
}

func (dog *Dog) Grow() {
    dog.Age++
}
func (dog *Dog) Move(address string) string {
    oldAddr := dog.address
    dog.address = address
    return oldAddr
}

上面的&d表示取地址操作哈扮。在下面會(huì)描寫這部分的。而interface{}(&d)返回的類型用 reflect.TypeOf 查看是*main.Dog蚓再。需要說一下的是interface{}是空接口滑肉,它相當(dāng)于java中的Object。go中的任何類型都是它的實(shí)現(xiàn)類型摘仅。再緊隨其后的v.(Animal)是強(qiáng)制Dog類型轉(zhuǎn)換為Animal類靶庙。

指針

對(duì)于java小伙伴來說,指針娃属、地址等都只是概念性了解惶洲,不像C++中,直接操作地址膳犹、指針等恬吕。而C/C++的性能之所以高,指針功不可沒须床。但是在C/C++中的回收控制不太好铐料。所以下面從使用方面來了解一下指針與地址。
操作指針設(shè)計(jì)兩個(gè)字符——&*豺旬。簡(jiǎn)單的來說钠惩,&是取地址的,*是取值的族阅。
基本類型

    house := "wahaha"
    // 對(duì)字符串取地址, ptr類型為*string
    ptr := &house
    // 打印ptr的類型篓跛,地址
    fmt.Println(reflect.TypeOf(ptr), ptr)
        //對(duì)ptr取值操作
    fmt.Println(*ptr)

此時(shí)輸出結(jié)果為

*string 0xc00004c1c0
wahaha

如想再深入了解,可以參見我整理的C++中的指針坦刀。

對(duì)象類型
還是以上面的Dog類的Grow方法愧沟。

func (dog *Dog) Grow() {
    fmt.Println(&dog)
    dog.Age++
}

此時(shí)打印輸出的結(jié)果是 0xc000006028。

我們注意到了所有的方法中鲤遥,前面的都是*Dog沐寺,那么此時(shí)*Dog和Dog有什么區(qū)別呢?
此時(shí)的*Dog是Dog類的一個(gè)指針類型盖奈,簡(jiǎn)單點(diǎn)說混坞,Dog類型的對(duì)象在程序中有很多,怎么確定是你這個(gè)d來調(diào)用方法呢?就要用到指針類型究孕。上面的方法也叫指針方法啥酱。而如果是:

func (dog Dog) Grow() {
    dog.Age++
}

此時(shí)就會(huì)將你的d復(fù)制一份,而復(fù)制的這一份與原來的d只有數(shù)值的相同而已厨诸,兩者不共用地址懈涛,所以在func (dog Dog) Grow()方法中,計(jì)算完后泳猬,函數(shù)的入?yún)og就沒有再用了批钠,也就是此時(shí)復(fù)制的這一份沒有再用了,就會(huì)進(jìn)行銷毀得封,而且這個(gè)復(fù)制對(duì)象的生存與否與d沒有任何關(guān)系埋心,也不會(huì)影響d的數(shù)值變化。這個(gè)方法也叫值方法忙上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拷呆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子疫粥,更是在濱河造成了極大的恐慌茬斧,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梗逮,死亡現(xiàn)場(chǎng)離奇詭異项秉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)慷彤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門娄蔼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人底哗,你說我怎么就攤上這事岁诉。” “怎么了跋选?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵涕癣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我前标,道長(zhǎng)坠韩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任候生,我火速辦了婚禮同眯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唯鸭。我一直安慰自己,他們只是感情好硅确,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布目溉。 她就那樣靜靜地躺著明肮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缭付。 梳的紋絲不亂的頭發(fā)上柿估,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音陷猫,去河邊找鬼秫舌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绣檬,可吹牛的內(nèi)容都是我干的足陨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼娇未,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼墨缘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起零抬,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤镊讼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后平夜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝶棋,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年忽妒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚼松。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鳖轰,靈堂內(nèi)的尸體忽然破棺而出傲醉,到底是詐尸還是另有隱情,我是刑警寧澤罕偎,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站京闰,受9級(jí)特大地震影響颜及,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹂楣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一俏站、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痊土,春花似錦肄扎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旭等。三九已至,卻和暖如春衡载,著一層夾襖步出監(jiān)牢的瞬間搔耕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工痰娱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弃榨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓梨睁,卻偏偏與公主長(zhǎng)得像鲸睛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子而姐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344