在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ 2.2 Go基礎(chǔ)
7 文本處理
3 Web基礎(chǔ)
14 擴(kuò)展Web框架
10.4 小結(jié)
2.2 Go基礎(chǔ)
2.8 總結(jié)
6.1 session和cookie
5.5 使用beedb庫進(jìn)行ORM開發(fā)
8.3 REST
13.6 小結(jié)
5.4 使用PostgreSQL數(shù)據(jù)庫
14.6 pprof支持
14.1 靜態(tài)文件支持
11.2 使用GDB調(diào)試
7.7 小結(jié)
1 GO環(huán)境配置
14.5 多語言支持
7.1 XML處理
1.5 總結(jié)
13 如何設(shè)計(jì)一個(gè)Web框架
14.3 表單及驗(yàn)證支持
12 部署與維護(hù)
10 國際化和本地化
1.1 Go 安裝
6.2 Go如何使用session
5.6 NOSQL數(shù)據(jù)庫操作
6.5 小結(jié)
9.4 避免SQL注入
12.1 應(yīng)用日志
4.2 驗(yàn)證表單的輸入
10.1 設(shè)置默認(rèn)地區(qū)
1.3 Go 命令
9.6 加密和解密數(shù)據(jù)
4.1 處理表單的輸入
4.4 防止多次遞交表單
11.3 Go怎么寫測試用例
8 Web服務(wù)
12.3 應(yīng)用部署
5.7 小結(jié)
12.5 小結(jié)
11 錯(cuò)誤處理,調(diào)試和測試
9.2 確保輸入過濾
14.2 Session支持
6.4 預(yù)防session劫持
12.4 備份和恢復(fù)
8.1 Socket編程
13.1 項(xiàng)目規(guī)劃
13.4 日志和配置設(shè)計(jì)
7.6 字符串處理
13.2 自定義路由器設(shè)計(jì)
6.3 session存儲(chǔ)
3.4 Go的http包詳解
8.2 WebSocket
10.3 國際化站點(diǎn)
7.5 文件操作
7.4 模板處理
9.1 預(yù)防CSRF攻擊
13.3 controller設(shè)計(jì)
2.6 interface
14.4 用戶認(rèn)證
2.3 流程和函數(shù)
附錄A 參考資料
11.1 錯(cuò)誤處理
9.5 存儲(chǔ)密碼
9.3 避免XSS攻擊
12.2 網(wǎng)站錯(cuò)誤處理
6 session和數(shù)據(jù)存儲(chǔ)
2.4 struct類型
3.3 Go如何使得Web工作
2.5 面向?qū)ο?/span>
3.1 Web工作方式
1.2 GOPATH與工作空間
2.1 你好,Go
9.7 小結(jié)
13.5 實(shí)現(xiàn)博客的增刪改
7.2 JSON處理
10.2 本地化資源
7.3 正則處理
2 Go語言基礎(chǔ)
5.1 database/sql接口
4.5 處理文件上傳
8.5 小結(jié)
4.3 預(yù)防跨站腳本
5.3 使用SQLite數(shù)據(jù)庫
14.7 小結(jié)
3.2 Go搭建一個(gè)Web服務(wù)器
2.7 并發(fā)
5 訪問數(shù)據(jù)庫
4 表單
3.5 小結(jié)
1.4 Go開發(fā)工具
11.4 小結(jié)
9 安全與加密
5.2 使用MySQL數(shù)據(jù)庫
4.6 小結(jié)
8.4 RPC

2.2 Go基礎(chǔ)

這小節(jié)我們將要介紹如何定義變量、常量、Go內(nèi)置類型以及Go程序設(shè)計(jì)中的一些技巧。

定義變量

Go語言里面定義變量有多種方式。

使用var關(guān)鍵字是Go最基本的定義變量方式,與C語言不同的是Go把變量類型放在變量名后面:

//定義一個(gè)名稱為“variableName”,類型為"type"的變量
var variableName type

定義多個(gè)變量

//定義三個(gè)類型都是“type”的變量
var vname1, vname2, vname3 type

定義變量并初始化值

//初始化“variableName”的變量為“value”值,類型是“type”
var variableName type = value

同時(shí)初始化多個(gè)變量

/*
    定義三個(gè)類型都是"type"的變量,并且分別初始化為相應(yīng)的值
    vname1為v1,vname2為v2,vname3為v3
*/
var vname1, vname2, vname3 type= v1, v2, v3

你是不是覺得上面這樣的定義有點(diǎn)繁瑣?沒關(guān)系,因?yàn)镚o語言的設(shè)計(jì)者也發(fā)現(xiàn)了,有一種寫法可以讓它變得簡單一點(diǎn)。我們可以直接忽略類型聲明,那么上面的代碼變成這樣了:

/*
    定義三個(gè)變量,它們分別初始化為相應(yīng)的值
    vname1為v1,vname2為v2,vname3為v3
    然后Go會(huì)根據(jù)其相應(yīng)值的類型來幫你初始化它們
*/
var vname1, vname2, vname3 = v1, v2, v3

你覺得上面的還是有些繁瑣?好吧,我也覺得。讓我們繼續(xù)簡化:

/*
    定義三個(gè)變量,它們分別初始化為相應(yīng)的值
    vname1為v1,vname2為v2,vname3為v3
    編譯器會(huì)根據(jù)初始化的值自動(dòng)推導(dǎo)出相應(yīng)的類型
*/
vname1, vname2, vname3 := v1, v2, v3

現(xiàn)在是不是看上去非常簡潔了?:=這個(gè)符號直接取代了vartype,這種形式叫做簡短聲明。不過它有一個(gè)限制,那就是它只能用在函數(shù)內(nèi)部;在函數(shù)外部使用則會(huì)無法編譯通過,所以一般用var方式來定義全局變量。

_(下劃線)是個(gè)特殊的變量名,任何賦予它的值都會(huì)被丟棄。在這個(gè)例子中,我們將值35賦予b,并同時(shí)丟棄34

_, b := 34, 35

Go對于已聲明但未使用的變量會(huì)在編譯階段報(bào)錯(cuò),比如下面的代碼就會(huì)產(chǎn)生一個(gè)錯(cuò)誤:聲明了i但未使用。

package main

func main() {
    var i int
}

常量

所謂常量,也就是在程序編譯階段就確定下來的值,而程序在運(yùn)行時(shí)無法改變該值。在Go程序中,常量可定義為數(shù)值、布爾值或字符串等類型。

它的語法如下:

const constantName = value
//如果需要,也可以明確指定常量的類型:
const Pi float32 = 3.1415926

下面是一些常量聲明的例子:

const Pi = 3.1415926
const i = 10000
const MaxThread = 10
const prefix = "astaxie_"

Go 常量和一般程序語言不同的是,可以指定相當(dāng)多的小數(shù)位數(shù)(例如200位), 若指定給float32自動(dòng)縮短為32bit,指定給float64自動(dòng)縮短為64bit,詳情參考鏈接

內(nèi)置基礎(chǔ)類型

Boolean

在Go中,布爾值的類型為bool,值是truefalse,默認(rèn)為false

//示例代碼
var isActive bool  // 全局變量聲明
var enabled, disabled = true, false  // 忽略類型的聲明
func test() {
    var available bool  // 一般聲明
    valid := false      // 簡短聲明
    available = true    // 賦值操作
}

數(shù)值類型

整數(shù)類型有無符號和帶符號兩種。Go同時(shí)支持intuint,這兩種類型的長度相同,但具體長度取決于不同編譯器的實(shí)現(xiàn)。Go里面也有直接定義好位數(shù)的類型:rune, int8, int16, int32, int64byte, uint8, uint16, uint32, uint64。其中runeint32的別稱,byteuint8的別稱。

需要注意的一點(diǎn)是,這些類型的變量之間不允許互相賦值或操作,不然會(huì)在編譯時(shí)引起編譯器報(bào)錯(cuò)。

如下的代碼會(huì)產(chǎn)生錯(cuò)誤:invalid operation: a + b (mismatched types int8 and int32)

var a int8

var b int32

c:=a + b

另外,盡管int的長度是32 bit, 但int 與 int32并不可以互用。

浮點(diǎn)數(shù)的類型有float32float64兩種(沒有float類型),默認(rèn)是float64。

這就是全部嗎?No!Go還支持復(fù)數(shù)。它的默認(rèn)類型是complex128(64位實(shí)數(shù)+64位虛數(shù))。如果需要小一些的,也有complex64(32位實(shí)數(shù)+32位虛數(shù))。復(fù)數(shù)的形式為RE + IMi,其中RE是實(shí)數(shù)部分,IM是虛數(shù)部分,而最后的i是虛數(shù)單位。下面是一個(gè)使用復(fù)數(shù)的例子:

var c complex64 = 5+5i
//output: (5+5i)
fmt.Printf("Value is: %v", c)

字符串

我們在上一節(jié)中講過,Go中的字符串都是采用UTF-8字符集編碼。字符串是用一對雙引號("")或反引號(` `)括起來定義,它的類型是string。

//示例代碼
var frenchHello string  // 聲明變量為字符串的一般方法
var emptyString string = ""  // 聲明了一個(gè)字符串變量,初始化為空字符串
func test() {
    no, yes, maybe := "no", "yes", "maybe"  // 簡短聲明,同時(shí)聲明多個(gè)變量
    japaneseHello := "Konichiwa"  // 同上
    frenchHello = "Bonjour"  // 常規(guī)賦值
}

在Go中字符串是不可變的,例如下面的代碼編譯時(shí)會(huì)報(bào)錯(cuò):cannot assign to s[0]

var s string = "hello"
s[0] = 'c'

但如果真的想要修改怎么辦呢?下面的代碼可以實(shí)現(xiàn):

s := "hello"
c := []byte(s)  // 將字符串 s 轉(zhuǎn)換為 []byte 類型
c[0] = 'c'
s2 := string(c)  // 再轉(zhuǎn)換回 string 類型
fmt.Printf("%s\n", s2)

Go中可以使用+操作符來連接兩個(gè)字符串:

s := "hello,"
m := " world"
a := s + m
fmt.Printf("%s\n", a)

修改字符串也可寫為:

s := "hello"
s = "c" + s[1:] // 字符串雖不能更改,但可進(jìn)行切片操作
fmt.Printf("%s\n", s)

如果要聲明一個(gè)多行的字符串怎么辦?可以通過`來聲明:

m := `hello
    world`

` 括起的字符串為Raw字符串,即字符串在代碼中的形式就是打印時(shí)的形式,它沒有字符轉(zhuǎn)義,換行也將原樣輸出。例如本例中會(huì)輸出:

hello
    world

錯(cuò)誤類型

Go內(nèi)置有一個(gè)error類型,專門用來處理錯(cuò)誤信息,Go的package里面還專門有一個(gè)包errors來處理錯(cuò)誤:

err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
    fmt.Print(err)
}

Go數(shù)據(jù)底層的存儲(chǔ)

下面這張圖來源于Russ Cox Blog中一篇介紹Go數(shù)據(jù)結(jié)構(gòu)的文章,大家可以看到這些基礎(chǔ)類型底層都是分配了一塊內(nèi)存,然后存儲(chǔ)了相應(yīng)的值。

http://wiki.jikexueyuan.com/project/go-web-programming/images/2.2.basic.png" alt="" />

圖2.1 Go數(shù)據(jù)格式的存儲(chǔ)

一些技巧

分組聲明

在Go語言中,同時(shí)聲明多個(gè)常量、變量,或者導(dǎo)入多個(gè)包時(shí),可采用分組的方式進(jìn)行聲明。

例如下面的代碼:

import "fmt"
import "os"

const i = 100
const pi = 3.1415
const prefix = "Go_"

var i int
var pi float32
var prefix string

可以分組寫成如下形式:

import(
    "fmt"
    "os"
)

const(
    i = 100
    pi = 3.1415
    prefix = "Go_"
)

var(
    i int
    pi float32
    prefix string
)

iota枚舉

Go里面有一個(gè)關(guān)鍵字iota,這個(gè)關(guān)鍵字用來聲明enum的時(shí)候采用,它默認(rèn)開始值是0,const中每增加一行加1:

const(
    x = iota  // x == 0
    y = iota  // y == 1
    z = iota  // z == 2
    w  // 常量聲明省略值時(shí),默認(rèn)和之前一個(gè)值的字面相同。這里隱式地說w = iota,因此w == 3。其實(shí)上面y和z可同樣不用"= iota"
)

const v = iota // 每遇到一個(gè)const關(guān)鍵字,iota就會(huì)重置,此時(shí)v == 0

const ( 
  e, f, g = iota, iota, iota //e=0,f=0,g=0 iota在同一行值相同
)

const (
    a = iota    a=0
    b = "B"
    c = iota    //c=2
    d,e,f = iota,iota,iota //d=3,e=3,f=3
    g //g = 4
)

除非被顯式設(shè)置為其它值或iota,每個(gè)const分組的第一個(gè)常量被默認(rèn)設(shè)置為它的0值,第二及后續(xù)的常量被默認(rèn)設(shè)置為它前面那個(gè)常量的值,如果前面那個(gè)常量的值是iota,則它也被設(shè)置為iota。

Go程序設(shè)計(jì)的一些規(guī)則

Go之所以會(huì)那么簡潔,是因?yàn)樗幸恍┠J(rèn)的行為:

  • 大寫字母開頭的變量是可導(dǎo)出的,也就是其它包可以讀取的,是公用變量;小寫字母開頭的就是不可導(dǎo)出的,是私有變量。
  • 大寫字母開頭的函數(shù)也是一樣,相當(dāng)于class中的帶public關(guān)鍵詞的公有函數(shù);小寫字母開頭的就是有private關(guān)鍵詞的私有函數(shù)。

array、slice、map

array

array就是數(shù)組,它的定義方式如下:

var arr [n]type

[n]type中,n表示數(shù)組的長度,type表示存儲(chǔ)元素的類型。對數(shù)組的操作和其它語言類似,都是通過[]來進(jìn)行讀取或賦值:

var arr [10]int  // 聲明了一個(gè)int類型的數(shù)組
arr[0] = 42      // 數(shù)組下標(biāo)是從0開始的
arr[1] = 13      // 賦值操作
fmt.Printf("The first element is %d\n", arr[0])  // 獲取數(shù)據(jù),返回42
fmt.Printf("The last element is %d\n", arr[9]) //返回未賦值的最后一個(gè)元素,默認(rèn)返回0

由于長度也是數(shù)組類型的一部分,因此[3]int[4]int是不同的類型,數(shù)組也就不能改變長度。數(shù)組之間的賦值是值的賦值,即當(dāng)把一個(gè)數(shù)組作為參數(shù)傳入函數(shù)的時(shí)候,傳入的其實(shí)是該數(shù)組的副本,而不是它的指針。如果要使用指針,那么就需要用到后面介紹的slice類型了。

數(shù)組可以使用另一種:=來聲明

a := [3]int{1, 2, 3} // 聲明了一個(gè)長度為3的int數(shù)組

b := [10]int{1, 2, 3} // 聲明了一個(gè)長度為10的int數(shù)組,其中前三個(gè)元素初始化為1、2、3,其它默認(rèn)為0

c := [...]int{4, 5, 6} // 可以省略長度而采用`...`的方式,Go會(huì)自動(dòng)根據(jù)元素個(gè)數(shù)來計(jì)算長度

也許你會(huì)說,我想數(shù)組里面的值還是數(shù)組,能實(shí)現(xiàn)嗎?當(dāng)然咯,Go支持嵌套數(shù)組,即多維數(shù)組。比如下面的代碼就聲明了一個(gè)二維數(shù)組:

// 聲明了一個(gè)二維數(shù)組,該數(shù)組以兩個(gè)數(shù)組作為元素,其中每個(gè)數(shù)組中又有4個(gè)int類型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}

// 上面的聲明可以簡化,直接忽略內(nèi)部的類型
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}

數(shù)組的分配如下所示:

http://wiki.jikexueyuan.com/project/go-web-programming/images/2.2.array.png" alt="" />

圖2.2 多維數(shù)組的映射關(guān)系

slice

在很多應(yīng)用場景中,數(shù)組并不能滿足我們的需求。在初始定義數(shù)組時(shí),我們并不知道需要多大的數(shù)組,因此我們就需要“動(dòng)態(tài)數(shù)組”。在Go里面這種數(shù)據(jù)結(jié)構(gòu)叫slice

slice并不是真正意義上的動(dòng)態(tài)數(shù)組,而是一個(gè)引用類型。slice總是指向一個(gè)底層array,slice的聲明也可以像array一樣,只是不需要長度。

// 和聲明array一樣,只是少了長度
var fslice []int

接下來我們可以聲明一個(gè)slice,并初始化數(shù)據(jù),如下所示:

slice := []byte {'a', 'b', 'c', 'd'}

slice可以從一個(gè)數(shù)組或一個(gè)已經(jīng)存在的slice中再次聲明。slice通過array[i:j]來獲取,其中i是數(shù)組的開始位置,j是結(jié)束位置,但不包含array[j],它的長度是j-i。

// 聲明一個(gè)含有10個(gè)元素元素類型為byte的數(shù)組
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

// 聲明兩個(gè)含有byte的slice
var a, b []byte

// a指向數(shù)組的第3個(gè)元素開始,并到第五個(gè)元素結(jié)束,
a = ar[2:5]
//現(xiàn)在a含有的元素: ar[2]、ar[3]和ar[4]

// b是數(shù)組ar的另一個(gè)slice
b = ar[3:5]
// b的元素是:ar[3]和ar[4]

注意slice和數(shù)組在聲明時(shí)的區(qū)別:聲明數(shù)組時(shí),方括號內(nèi)寫明了數(shù)組的長度或使用...自動(dòng)計(jì)算長度,而聲明slice時(shí),方括號內(nèi)沒有任何字符。

它們的數(shù)據(jù)結(jié)構(gòu)如下所示

http://wiki.jikexueyuan.com/project/go-web-programming/images/2.2.slice.png" alt="" />

圖2.3 slice和array的對應(yīng)關(guān)系圖

slice有一些簡便的操作

  • slice的默認(rèn)開始位置是0,ar[:n]等價(jià)于ar[0:n]
  • slice的第二個(gè)序列默認(rèn)是數(shù)組的長度,ar[n:]等價(jià)于ar[n:len(ar)]
  • 如果從一個(gè)數(shù)組里面直接獲取slice,可以這樣ar[:],因?yàn)槟J(rèn)第一個(gè)序列是0,第二個(gè)是數(shù)組的長度,即等價(jià)于ar[0:len(ar)]

下面這個(gè)例子展示了更多關(guān)于slice的操作:

// 聲明一個(gè)數(shù)組
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 聲明兩個(gè)slice
var aSlice, bSlice []byte

// 演示一些簡便操作
aSlice = array[:3] // 等價(jià)于aSlice = array[0:3] aSlice包含元素: a,b,c
aSlice = array[5:] // 等價(jià)于aSlice = array[5:10] aSlice包含元素: f,g,h,i,j
aSlice = array[:]  // 等價(jià)于aSlice = array[0:10] 這樣aSlice包含了全部的元素

// 從slice中獲取slice
aSlice = array[3:7]  // aSlice包含元素: d,e,f,g,len=4,cap=7
bSlice = aSlice[1:3] // bSlice 包含aSlice[1], aSlice[2] 也就是含有: e,f
bSlice = aSlice[:3]  // bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是含有: d,e,f
bSlice = aSlice[0:5] // 對slice的slice可以在cap范圍內(nèi)擴(kuò)展,此時(shí)bSlice包含:d,e,f,g,h
bSlice = aSlice[:]   // bSlice包含所有aSlice的元素: d,e,f,g

slice是引用類型,所以當(dāng)引用改變其中元素的值時(shí),其它的所有引用都會(huì)改變該值,例如上面的aSlicebSlice,如果修改了aSlice中元素的值,那么bSlice相對應(yīng)的值也會(huì)改變。

從概念上面來說slice像一個(gè)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體包含了三個(gè)元素:

  • 一個(gè)指針,指向數(shù)組中slice指定的開始位置
  • 長度,即slice的長度
  • 最大長度,也就是slice開始位置到數(shù)組的最后位置的長度

      Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
      Slice_a := Array_a[2:5]

上面代碼的真正存儲(chǔ)結(jié)構(gòu)如下圖所示

http://wiki.jikexueyuan.com/project/go-web-programming/images/2.2.slice2.png" alt="" />

圖2.4 slice對應(yīng)數(shù)組的信息

對于slice有幾個(gè)有用的內(nèi)置函數(shù):

  • len 獲取slice的長度
  • cap 獲取slice的最大容量
  • appendslice里面追加一個(gè)或者多個(gè)元素,然后返回一個(gè)和slice一樣類型的slice
  • copy 函數(shù)copy從源slicesrc中復(fù)制元素到目標(biāo)dst,并且返回復(fù)制的元素的個(gè)數(shù)

注:append函數(shù)會(huì)改變slice所引用的數(shù)組的內(nèi)容,從而影響到引用同一數(shù)組的其它slice。 但當(dāng)slice中沒有剩余空間(即(cap-len) == 0)時(shí),此時(shí)將動(dòng)態(tài)分配新的數(shù)組空間。返回的slice數(shù)組指針將指向這個(gè)空間,而原數(shù)組的內(nèi)容將保持不變;其它引用此數(shù)組的slice則不受影響。

從Go1.2開始slice支持了三個(gè)參數(shù)的slice,之前我們一直采用這種方式在slice或者array基礎(chǔ)上來獲取一個(gè)slice

var array [10]int
slice := array[2:4]

這個(gè)例子里面slice的容量是8,新版本里面可以指定這個(gè)容量

slice = array[2:4:7]

上面這個(gè)的容量就是7-2,即5。這樣這個(gè)產(chǎn)生的新的slice就沒辦法訪問最后的三個(gè)元素。

如果slice是這樣的形式array[:i:j],即第一個(gè)參數(shù)為空,默認(rèn)值就是0。

map

map也就是Python中字典的概念,它的格式為map[keyType]valueType

我們看下面的代碼,map的讀取和設(shè)置也類似slice一樣,通過key來操作,只是sliceindex只能是`int`類型,而map多了很多類型,可以是int,可以是string及所有完全定義了==!=操作的類型。

// 聲明一個(gè)key是字符串,值為int的字典,這種方式的聲明需要在使用之前使用make初始化
var numbers map[string]int
// 另一種map的聲明方式
numbers := make(map[string]int)
numbers["one"] = 1  //賦值
numbers["ten"] = 10 //賦值
numbers["three"] = 3

fmt.Println("第三個(gè)數(shù)字是: ", numbers["three"]) // 讀取數(shù)據(jù)
// 打印出來如:第三個(gè)數(shù)字是: 3

這個(gè)map就像我們平??吹降谋砀褚粯樱筮吜惺?code>key,右邊列是值

使用map過程中需要注意的幾點(diǎn):

  • map是無序的,每次打印出來的map都會(huì)不一樣,它不能通過index獲取,而必須通過key獲取
  • map的長度是不固定的,也就是和slice一樣,也是一種引用類型
  • 內(nèi)置的len函數(shù)同樣適用于map,返回map擁有的key的數(shù)量
  • map的值可以很方便的修改,通過numbers["one"]=11可以很容易的把key為one的字典值改為11
  • map和其他基本型別不同,它不是thread-safe,在多個(gè)go-routine存取時(shí),必須使用mutex lock機(jī)制

map的初始化可以通過key:val的方式初始化值,同時(shí)map內(nèi)置有判斷是否存在key的方式

通過delete刪除map的元素:

// 初始化一個(gè)字典
rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 }
// map有兩個(gè)返回值,第二個(gè)返回值,如果不存在key,那么ok為false,如果存在ok為true
csharpRating, ok := rating["C#"]
if ok {
    fmt.Println("C# is in the map and its rating is ", csharpRating)
} else {
    fmt.Println("We have no rating associated with C# in the map")
}

delete(rating, "C")  // 刪除key為C的元素

上面說過了,map也是一種引用類型,如果兩個(gè)map同時(shí)指向一個(gè)底層,那么一個(gè)改變,另一個(gè)也相應(yīng)的改變:

m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut"  // 現(xiàn)在m["hello"]的值已經(jīng)是Salut了

make、new操作

make用于內(nèi)建類型(mapslicechannel)的內(nèi)存分配。new用于各種類型的內(nèi)存分配。

內(nèi)建函數(shù)new本質(zhì)上說跟其它語言中的同名函數(shù)功能一樣:new(T)分配了零值填充的T類型的內(nèi)存空間,并且返回其地址,即一個(gè)*T類型的值。用Go的術(shù)語說,它返回了一個(gè)指針,指向新分配的類型T的零值。有一點(diǎn)非常重要:

new返回指針。

內(nèi)建函數(shù)make(T, args)new(T)有著不同的功能,make只能創(chuàng)建slice、mapchannel,并且返回一個(gè)有初始值(非零)的T類型,而不是*T。本質(zhì)來講,導(dǎo)致這三個(gè)類型有所不同的原因是指向數(shù)據(jù)結(jié)構(gòu)的引用在使用前必須被初始化。例如,一個(gè)slice,是一個(gè)包含指向數(shù)據(jù)(內(nèi)部array)的指針、長度和容量的三項(xiàng)描述符;在這些項(xiàng)目被初始化之前,slicenil。對于slice、mapchannel來說,make初始化了內(nèi)部的數(shù)據(jù)結(jié)構(gòu),填充適當(dāng)?shù)闹怠?/p>

make返回初始化后的(非零)值。

下面這個(gè)圖詳細(xì)的解釋了newmake之間的區(qū)別。

http://wiki.jikexueyuan.com/project/go-web-programming/images/2.2.makenew.png" alt="" />

圖2.5 make和new對應(yīng)底層的內(nèi)存分配

零值

關(guān)于“零值”,所指并非是空值,而是一種“變量未填充前”的默認(rèn)值,通常為0。 此處羅列 部分類型 的 “零值”

int     0
int8    0
int32   0
int64   0
uint    0x0
rune    0 //rune的實(shí)際類型是 int32
byte    0x0 // byte的實(shí)際類型是 uint8
float32 0 //長度為 4 byte
float64 0 //長度為 8 byte
bool    false
string  ""
上一篇:1.1 Go 安裝下一篇:12.5 小結(jié)