熟悉C語言的同學(xué)都知道,查看一個變量的地址在處理指針的相關(guān)問題的時候直觀重要,在C中直接取地址符 即可。那么在Go語言中如何查看一個變量的地址,我們使用unsafe.Pointer() 函數(shù)來查看一個變量的內(nèi)存地址。
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、微信小程序、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了孟村免費建站歡迎大家使用!
舉例:
type Vertex struct {
X, Y float64
}
func (v Vertex) sqrt() float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
func (v Vertex) scale(f float64) { //帶 號 和不帶*號的區(qū)別 可以從內(nèi)存地址來看出
fmt.printf("=======", unsafe.Pointer(v))//v 本身就是指針 存儲的就是地址 不用取地址
v.X = x.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
fmt.printf("=======", unsafe.Pointer(v))
v.scale(10)
fmt.Println(v.sqrt())
}
//帶 號 打印的結(jié)果 ====== -%!(EXTRA unsafe.Pointer=0xc00006e070)======%!(EXTRA unsafe.Pointer=0xc00006e070) 相同
//不帶 號 打印的結(jié)果 ======%!(EXTRA unsafe.Pointer=0xc000094060)======%!(EXTRA unsafe.Pointer=0xc000094090) 不同
去掉*號 在scale()方法中要對 v 進行取地址操作
首先說一下go中的字符串類型:
字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個字節(jié)連接起來的。Go語言的字符串的字節(jié)使用UTF-8編碼標(biāo)識Unicode文本。
下面介紹字符串的三種遍歷方式,根據(jù)實際情況選擇即可。
該遍歷方式==缺點==:遍歷是按照字節(jié)遍歷,因此如果有中文等非英文字符,就會出現(xiàn)亂碼,比如要遍歷"abc北京"這個字符串,效果如下:
可見這不是我們想要的效果,根據(jù)utf-8中文編碼規(guī)則,我們要str[3]str[4]str[5]三個字節(jié)合起來組成“北”字及 str[6]str[7]str[8]合起來組成“京”字。由此引出下面第二種遍歷方法。
該方式是按照字符遍歷的,所以不會出現(xiàn)亂碼,如下:
運行結(jié)果:
從圖中可以看到第二個漢子“京”的開始下標(biāo)是6,直接跳過了4和5,可見確實依照utf8編碼方式將三個字節(jié)組合成了一個漢字,str[3]-str[5]組合成“北”字,str[6]-str[8]組合成了“京”字。
由于下標(biāo)的不確定性,所以引出了下面的遍歷方式。
1 可以先將字符串轉(zhuǎn)成 []rune 切片
2 再用常規(guī)方法進行遍歷
運行效果:
由此可見下標(biāo)是按1遞增的,沒有產(chǎn)生跳躍現(xiàn)象。
在Go語言中有一些調(diào)試技巧能幫助我們快速找到問題,有時候你想盡可能多的記錄異常但仍覺得不夠,搞清楚堆棧的意義有助于定位Bug或者記錄更完整的信息。
本文將討論堆棧跟蹤信息以及如何在堆棧中識別函數(shù)所傳遞的參數(shù)。
Functions
先從這段代碼開始:
Listing 1
01 package main
02
03 func main() {
04 ? ? slice := make([]string, 2, 4)
05 ? ? Example(slice, "hello", 10)
06 }
07
08 func Example(slice []string, str string, i int) {
09 ? ? panic("Want stack trace")
10 }
Example函數(shù)定義了3個參數(shù),1個string類型的slice, 1個string和1個integer, 并且拋出了panic,運行這段代碼可以看到這樣的結(jié)果:
Listing 2
Panic: Want stack trace
goroutine 1 [running]:
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:9 +0x64
main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:5 +0x85
goroutine 2 [runnable]:
runtime.forcegchelper()
/Users/bill/go/src/runtime/proc.go:90
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 3 [runnable]:
runtime.bgsweep()
/Users/bill/go/src/runtime/mgc0.go:82
runtime.goexit()
/Users/bill/go/src/runtime/asm_amd64.s:2232 +0x1
堆棧信息中顯示了在panic拋出這個時間所有的goroutines狀態(tài),發(fā)生的panic的goroutine會顯示在最上面。
Listing 3
01 goroutine 1 [running]:
02 main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:9 +0x64
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:5 +0x85
第1行顯示最先發(fā)出panic的是goroutine 1, 第二行顯示panic位于main.Example中, 并能定位到該行代碼,在本例中第9行引發(fā)了panic。
下面我們關(guān)注參數(shù)是如何傳遞的:
Listing 4
// Declaration
main.Example(slice []string, str string, i int)
// Call to Example by main.
slice := make([]string, 2, 4)
Example(slice, "hello", 10)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
這里展示了在main中帶參數(shù)調(diào)用Example函數(shù)時的堆棧信息,比較就能發(fā)現(xiàn)兩者的參數(shù)數(shù)量并不相同,Example定義了3個參數(shù),堆棧中顯示了6個參數(shù)?,F(xiàn)在的關(guān)鍵問題是我們要弄清楚它們是如何匹配的。
第1個參數(shù)是string類型的slice,我們知道在Go語言中slice是引用類型,即slice變量結(jié)構(gòu)會包含三個部分:指針、長度(Lengthe)、容量(Capacity)
Listing 5
// Slice parameter value
slice := make([]string, 2, 4)
// Slice header values
Pointer: ?0x2080c3f50
Length: ? 0x2
Capacity: 0x4
// Declaration
main.Example(slice []string, str string, i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5, 0xa)
因此,前面3個參數(shù)會匹配slice, 如下圖所示:
Figure 1
figure provided by Georgi Knox
我們現(xiàn)在來看第二個參數(shù),它是string類型,string類型也是引用類型,它包括兩部分:指針、長度。
Listing 6
// String parameter value
"hello"
// String header values
Pointer: 0x425c0
Length: ?0x5
// Declaration
main.Example(slice []string,?str string, i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4,?0x425c0, 0x5, 0xa)
可以確定,堆棧信息中第4、5兩個參數(shù)對應(yīng)代碼中的string參數(shù),如下圖所示:
Figure 2
figure provided by Georgi Knox
最后一個參數(shù)integer是single word值。
Listing 7
// Integer parameter value
10
// Integer value
Base 16: 0xa
// Declaration
main.Example(slice []string, str string,?i int)
// Stack trace
main.Example(0x2080c3f50, 0x2, 0x4, 0x425c0, 0x5,?0xa)
現(xiàn)在我們可以匹配代碼中的參數(shù)到堆棧信息了。
Figure 3
figure provided by Georgi Knox
Methods
如果我們將Example作為結(jié)構(gòu)體的方法會怎么樣呢?
Listing 8
01 package main
02
03 import "fmt"
04
05 type trace struct{}
06
07 func main() {
08 ? ? slice := make([]string, 2, 4)
09
10 ? ? var t trace
11 ? ? t.Example(slice, "hello", 10)
12 }
13
14 func (t *trace) Example(slice []string, str string, i int) {
15 ? ? fmt.Printf("Receiver Address: %p\n", t)
16 ? ? panic("Want stack trace")
17 }
如上所示修改代碼,將Example定義為trace的方法,并通過trace的實例t來調(diào)用Example。
再次運行程序,會發(fā)現(xiàn)堆棧信息有一點不同:
Listing 9
Receiver Address:?0x1553a8
panic: Want stack trace
01 goroutine 1 [running]:
02 main.(*trace).Example(0x1553a8, 0x2081b7f50, 0x2, 0x4, 0xdc1d0, 0x5, 0xa)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:16 +0x116
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:11 +0xae
首先注意第2行的方法調(diào)用使用了pointer receiver,在package名字和方法名之間多出了"*trace"字樣。另外,參數(shù)列表的第1個參數(shù)標(biāo)明了結(jié)構(gòu)體(t)地址。我們從堆棧信息中看到了內(nèi)部實現(xiàn)細節(jié)。
Packing
如果有多個參數(shù)可以填充到一個single word, 則這些參數(shù)值會合并打包:
Listing 10
01 package main
02
03 func main() {
04 ? ? Example(true, false, true, 25)
05 }
06?
07 func Example(b1, b2, b3 bool, i uint8) {
08 ? ? panic("Want stack trace")
09 }
這個例子修改Example函數(shù)為4個參數(shù):3個bool型和1個八位無符號整型。bool值也是用8個bit表示,所以在32位和64位架構(gòu)下,4個參數(shù)可以合并為一個single word。
Listing 11
01 goroutine 1 [running]:
02 main.Example(0x19010001)
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:8 +0x64
03 main.main()
/Users/bill/Spaces/Go/Projects/src/github.com/goinaction/code/
temp/main.go:4 +0x32
這是本例的堆棧信息,看下圖的具體分析:
Listing 12
// Parameter values
true, false, true, 25
// Word value
Bits ? ?Binary ? ? ?Hex ? Value
00-07 ? 0000 0001 ??01? ??true
08-15 ? 0000 0000 ??00? ? false
16-23 ? 0000 0001 ??01? ? true
24-31 ? 0001 1001 ??19? ? 25
// Declaration
main.Example(b1, b2, b3 bool, i uint8)
// Stack trace
main.Example(0x19010001)
以上展示了參數(shù)值是如何匹配到4個參數(shù)的。當(dāng)我們看到堆棧信息中包括十六進制值,需要知道這些值是如何傳遞的。
Golang 和java/c不同,Go在不同類型的變量之間賦值時需要顯式轉(zhuǎn)換。也就是說Golang中數(shù)據(jù)類型不能自動轉(zhuǎn)換。
基本語法
表達式T(v))將值v 轉(zhuǎn)換為類型T
T∶就是數(shù)據(jù)類型,比如int32,int64,float32等等
v∶ 就是需要轉(zhuǎn)換的變量
var i int = 100
var b float64 = float64(i)
var c int64 = int64(b)
fmt.Printf("b=%f,c=%d",b,c)
b=100.000000,c=100
登錄后復(fù)制
細節(jié)說明
1)Go中,數(shù)據(jù)類型的轉(zhuǎn)換可以是從表示范圍小-表示范圍大,也可以范圍大一范圍小
2) 被轉(zhuǎn)換的是變量存儲的數(shù)據(jù)(即值),變量本身的數(shù)據(jù)類型并沒有變化!
3) 在轉(zhuǎn)換中,比如將 int64 轉(zhuǎn)成int8,編譯時不會報錯,只是轉(zhuǎn)換的結(jié)果是按溢出處理,和
我們希望的結(jié)果不一樣。(在轉(zhuǎn)換的時候需要注意范圍)
var a int64 = 10000000
var b int8 = int8(a)
fmt.Printf("%d",b)
-128
登錄后復(fù)制
可以看到在轉(zhuǎn)換的時候,一定要保證轉(zhuǎn)換大數(shù)據(jù)要是對方可以接受的范圍。
n1類型是int32,那么?20整個就是int32類型,可是n2是int64,這樣就會編譯錯誤。
題二n4是12 + 127溢出超過了范圍,運行的時候按照溢出處理。n3是直接編譯不通過,128已經(jīng)超過了int8類型的范圍
基本數(shù)據(jù)類型和string的轉(zhuǎn)換
字符串格式化
Go語言用于控制文本輸出常用的標(biāo)準(zhǔn)庫是fmt
fmt中主要用于輸出的函數(shù)有:
Print: 輸出到控制臺,不接受任何格式化操作
Println: 輸出到控制臺并換行
Printf : 只可以打印出格式化的字符串。只可以直接輸出字符串類型的變量(不可以輸出別的類型)
Sprintf:格式化并返回一個字符串而不帶任何輸出
Fprintf:來格式化并輸出到 io.Writers 而不是 os.Stdout
整數(shù)類型
格 式 描 述
%b 整型以二進制方式顯示
%o 整型以八進制方式顯示
%d 整型以十進制方式顯示
%x 整型以十六進制方式顯示
%X 整型以十六進制、字母大寫方式顯示
%c 相應(yīng)Unicode碼點所表示的字符
%U Unicode 字符, Unicode格式:123,等同于 "U+007B"
浮點數(shù)
格 式 描 述
%e 科學(xué)計數(shù)法,例如 -1234.456e+78
%E 科學(xué)計數(shù)法,例如 -1234.456E+78
%f 有小數(shù)點而無指數(shù),例如 123.456
%g 根據(jù)情況選擇 %e 或 %f 以產(chǎn)生更緊湊的(無末尾的0)輸出
%G 根據(jù)情況選擇 %E 或 %f 以產(chǎn)生更緊湊的(無末尾的0)輸出
布爾
格 式 描 述
%t true 或 false
字符串
格 式 描 述
%s 字符串或切片的無解譯字節(jié)
%q 雙引號圍繞的字符串,由Go語法安全地轉(zhuǎn)義
%x 十六進制,小寫字母,每字節(jié)兩個字符
%X 十六進制,大寫字母,每字節(jié)兩個字符
指針
格 式 描 述
%p 十六進制表示,前綴 0x
var num1 int64 = 99
var num2 float64 = 23.99
var b bool = true
var mychar byte = 'h'
str1 := fmt.Sprintf("%d",num1)
str2 := fmt.Sprintf("%f",num2)
bool1 := fmt.Sprintf("%t",b)
mychar1 := fmt.Sprintf("%c",mychar)
fmt.Printf("%T,%T,%T,str1=%v,str2=%v,bool1=%v,mychar1=%v",str1,bool1,str2,str1,str2,bool1,mychar1)
string,string,string,string,str1=99,str2=23.990000,bool1=true,mychar1=h
登錄后復(fù)制
?
使用strconv包 基本類型 - string類型
num1 := 99
str1 := strconv.FormatInt(int64(num1),10)
fmt.Printf("%T,%v",str1,str1)
num2 := 99.99
str2 := strconv.FormatFloat(num2,'f',10,64)
fmt.Printf("%T,%v\n",str2,str2)
登錄后復(fù)制
strconv包提供了字符串與簡單數(shù)據(jù)類型之間的類型轉(zhuǎn)換功能,可以將簡單類型轉(zhuǎn)換為字符串,也可以將字符串轉(zhuǎn)換為其它簡單類型
string和int轉(zhuǎn)換
int轉(zhuǎn)string的方法是: Itoa()
str := strconv.Itoa(100)
fmt.Printf("type %v, value: %s\n", reflect.TypeOf(str), str)
登錄后復(fù)制
2.string轉(zhuǎn)int的方法是:
i, err := strconv.Atoi("100")
fmt.Printf("type %v, value: %d, err: %v\n", reflect.TypeOf(i), i, err)
登錄后復(fù)制
并不是所有string都能轉(zhuǎn)化為int, 所以可能會報錯:
i, err := strconv.Atoi("100x")
fmt.Printf("type %v, value: %d, err: %v\n", reflect.TypeOf(i), i, err)
登錄后復(fù)制
使用strconv包 string轉(zhuǎn)其他類型
strconv包提供的Parse類函數(shù)用于將字符串轉(zhuǎn)化為給定類型的值:ParseBool()、ParseFloat()、ParseInt()、ParseUint() 由于字符串轉(zhuǎn)換為其它類型可能會失敗,所以這些函數(shù)都有兩個返回值,第一個返回值保存轉(zhuǎn)換后的值,第二個返回值判斷是否轉(zhuǎn)換成功。
1.轉(zhuǎn)bool
b, err := strconv.ParseBool("true")
fmt.Println(b, err)
登錄后復(fù)制
2.轉(zhuǎn)float
f1, err := strconv.ParseFloat("3.1", 32)
fmt.Println(f1, err)
f2, err := strconv.ParseFloat("3.1", 64)
fmt.Println(f2, err)
登錄后復(fù)制
由于浮點數(shù)的小數(shù)部分 并不是所有小數(shù)都能在計算機中精確的表示, 這就造成了浮點數(shù)精度問題, 比如下面
var n float64 = 0
for i := 0; i 1000; i++ {
n += .01
}
fmt.Println(n)
關(guān)于浮點數(shù)精度問題: c計算機不都是0101嗎,你有想過計算機是怎么表示的小數(shù)嗎, 簡單理解就是:
將其整數(shù)部分與小樹部分分開, 比如5.25
對于整數(shù)部分 5 ,我們使用"不斷除以2取余數(shù)"的方法,得到 101
對于小數(shù)部分 .25 ,我們使用"不斷乘以2取整數(shù)"的方法,得到 .01
聽說有一個包可以解決這個問題: github.com/shopspring/decimal
3.轉(zhuǎn)int
func ParseInt(s string, base int, bitSize int) (i int64, err error)
base: 進制,有效值為0、2-36。當(dāng)base=0的時候,表示根據(jù)string的前綴來判斷以什么進制去解析:0x開頭的以16進制的方式去解析,0開頭的以8進制方式去解析,其它的以10進制方式解析
bitSize: 多少位,有效值為0、8、16、32、64。當(dāng)bitSize=0的時候,表示轉(zhuǎn)換為int或uint類型。例如bitSize=8表示轉(zhuǎn)換后的值的類型為int8或uint8
fmt.Println(bInt8(-1)) // 0000 0001(原碼) - 1111 1110(反碼) - 1111 1111
// Parse 二進制字符串
i, err := strconv.ParseInt("11111111", 2, 16)
fmt.Println(i, err)
// Parse 十進制字符串
i, err = strconv.ParseInt("255", 10, 16)
fmt.Println(i, err)
// Parse 十六進制字符串
i, err = strconv.ParseInt("4E2D", 16, 16)
fmt.Println(i, err)
4.轉(zhuǎn)uint
func ParseUint(s string, base int, bitSize int) (uint64, error)
用法和轉(zhuǎn)int一樣, 只是轉(zhuǎn)換后的數(shù)據(jù)類型是uint64
u, err := strconv.ParseUint("11111111", 2, 16)
fmt.Println(u, err)
u, err = strconv.ParseUint("255", 10, 16)
fmt.Println(u, err)
u, err = strconv.ParseUint("4E2D", 16, 16)
fmt.Println(u, err)
其他類型轉(zhuǎn)string
將給定類型格式化為string類型:FormatBool()、FormatFloat()、FormatInt()、FormatUint()。
fmt.Println(strconv.FormatBool(true))
// 問題又來了
fmt.Println(strconv.FormatInt(255, 2))
fmt.Println(strconv.FormatInt(255, 10))
fmt.Println(strconv.FormatInt(255, 16))
fmt.Println(strconv.FormatUint(255, 2))
fmt.Println(strconv.FormatUint(255, 10))
fmt.Println(strconv.FormatUint(255, 16))
fmt.Println(strconv.FormatFloat(3.1415, 'E', -1, 64))
func FormatFloat(f float64, fmt byte, prec, bitSize int) string
bitSize表示f的來源類型(32:float32、64:float64),會據(jù)此進行舍入。
fmt表示格式:'f'(-ddd.dddd)、'b'(-ddddp±ddd,指數(shù)為二進制)、'e'(-d.dddde±dd,十進制指數(shù))、'E'(-d.ddddE±dd,十進制指數(shù))、'g'(指數(shù)很大時用'e'格式,否則'f'格式)、'G'(指數(shù)很大時用'E'格式,否則'f'格式)。
prec控制精度(排除指數(shù)部分):對'f'、'e'、'E',它表示小數(shù)點后的數(shù)字個數(shù);對'g'、'G',它控制總的數(shù)字個數(shù)。如果prec 為-1,則代表使用最少數(shù)量的、但又必需的數(shù)字來表示f。
本教程介紹了使用 Godatabase/sql及其標(biāo)準(zhǔn)庫中的包訪問關(guān)系數(shù)據(jù)庫的基礎(chǔ)知識。
您將使用的database/sql包包括用于連接數(shù)據(jù)庫、執(zhí)行事務(wù)、取消正在進行的操作等的類型和函數(shù)。
在本教程中,您將創(chuàng)建一個數(shù)據(jù)庫,然后編寫代碼來訪問該數(shù)據(jù)庫。您的示例項目將是有關(guān)老式爵士樂唱片的數(shù)據(jù)存儲庫。
首先,為您要編寫的代碼創(chuàng)建一個文件夾。
1、打開命令提示符并切換到您的主目錄。
在 Linux 或 Mac 上:
在 Windows 上:
2、在命令提示符下,為您的代碼創(chuàng)建一個名為 data-access 的目錄。
3、創(chuàng)建一個模塊,您可以在其中管理將在本教程中添加的依賴項。
運行g(shù)o mod init命令,為其提供新代碼的模塊路徑。
此命令創(chuàng)建一個 go.mod 文件,您添加的依賴項將在其中列出以供跟蹤。
注意: 在實際開發(fā)中,您會指定一個更符合您自己需求的模塊路徑。有關(guān)更多信息,請參閱一下文章。
GO語言(二十五):管理依賴項(上)
GO語言(二十六):管理依賴項(中)
GO語言(二十七):管理依賴項(下)
接下來,您將創(chuàng)建一個數(shù)據(jù)庫。
在此步驟中,您將創(chuàng)建要使用的數(shù)據(jù)庫。您將使用 DBMS 本身的 CLI 創(chuàng)建數(shù)據(jù)庫和表,以及添加數(shù)據(jù)。
您將創(chuàng)建一個數(shù)據(jù)庫,其中包含有關(guān)黑膠唱片上的老式爵士樂錄音的數(shù)據(jù)。
這里的代碼使用MySQL CLI,但大多數(shù) DBMS 都有自己的 CLI,具有類似的功能。
1、打開一個新的命令提示符。
在命令行,登錄到您的 DBMS,如下面的 MySQL 示例所示。
2、在mysql命令提示符下,創(chuàng)建一個數(shù)據(jù)庫。
3、切到您剛剛創(chuàng)建的數(shù)據(jù)庫,以便您可以添加表。
4、在文本編輯器的 data-access 文件夾中,創(chuàng)建一個名為 create-tables.sql 的文件來保存用于添加表的 SQL 腳本。
將以下 SQL 代碼粘貼到文件中,然后保存文件。
在此 SQL 代碼中:
(1)刪除名為album表。 首先執(zhí)行此命令可以讓您更輕松地稍后重新運行腳本。
(2)創(chuàng)建一個album包含四列的表:title、artist和price。每行的id值由 DBMS 自動創(chuàng)建。
(3)添加帶有值的四行。
5、在mysql命令提示符下,運行您剛剛創(chuàng)建的腳本。
您將使用以下形式的source命令:
6、在 DBMS 命令提示符處,使用SELECT語句來驗證您是否已成功創(chuàng)建包含數(shù)據(jù)的表。
接下來,您將編寫一些 Go 代碼進行連接,以便進行查詢。
現(xiàn)在你已經(jīng)有了一個包含一些數(shù)據(jù)的數(shù)據(jù)庫,開始你的 Go 代碼。
找到并導(dǎo)入一個數(shù)據(jù)庫驅(qū)動程序,該驅(qū)動程序會將您通過database/sql包中的函數(shù)發(fā)出的請求轉(zhuǎn)換為數(shù)據(jù)庫可以理解的請求。
1、在您的瀏覽器中,訪問SQLDrivers wiki 頁面以識別您可以使用的驅(qū)動程序。
2、使用頁面上的列表來識別您將使用的驅(qū)動程序。為了在本教程中訪問 MySQL,您將使用 Go-MySQL-Driver。
3、請注意驅(qū)動程序的包名稱 - 此處為github.com/go-sql-driver/mysql.
4、使用您的文本編輯器,創(chuàng)建一個用于編寫 Go 代碼的文件,并將該文件作為 main.go 保存在您之前創(chuàng)建的數(shù)據(jù)訪問目錄中。
5、進入main.go,粘貼以下代碼導(dǎo)入驅(qū)動包。
在此代碼中:
(1)將您的代碼添加到main包中,以便您可以獨立執(zhí)行它。
(2)導(dǎo)入 MySQL 驅(qū)動程序github.com/go-sql-driver/mysql。
導(dǎo)入驅(qū)動程序后,您將開始編寫代碼以訪問數(shù)據(jù)庫。
現(xiàn)在編寫一些 Go 代碼,讓您使用數(shù)據(jù)庫句柄訪問數(shù)據(jù)庫。
您將使用指向結(jié)構(gòu)的指針sql.DB,它表示對特定數(shù)據(jù)庫的訪問。
編寫代碼
1、進入 main.go,在import您剛剛添加的代碼下方,粘貼以下 Go 代碼以創(chuàng)建數(shù)據(jù)庫句柄。
在此代碼中:
(3)使用 MySQL 驅(qū)動程序Config和FormatDSN類型以收集連接屬性并將它們格式化為連接字符串的 DSN。
該Config結(jié)構(gòu)使代碼比連接字符串更容易閱讀。
(4)調(diào)用sql.Open 初始化db變量,傳遞 FormatDSN。
(5)檢查來自 的錯誤sql.Open。例如,如果您的數(shù)據(jù)庫連接細節(jié)格式不正確,它可能會失敗。
為了簡化代碼,您調(diào)用log.Fatal結(jié)束執(zhí)行并將錯誤打印到控制臺。在生產(chǎn)代碼中,您會希望以更優(yōu)雅的方式處理錯誤。
(6)調(diào)用DB.Ping以確認連接到數(shù)據(jù)庫有效。在運行時, sql.Open可能不會立即連接,具體取決于驅(qū)動程序。您在Ping此處使用以確認 database/sql包可以在需要時連接。
(7)檢查來自Ping的錯誤,以防連接失敗。
(8)Ping如果連接成功,則打印一條消息。
文件的頂部現(xiàn)在應(yīng)該如下所示:
3、保存 main.go。
1、開始跟蹤 MySQL 驅(qū)動程序模塊作為依賴項。
使用go get 添加 github.com/go-sql-driver/mysql 模塊作為您自己模塊的依賴項。使用點參數(shù)表示“獲取當(dāng)前目錄中代碼的依賴項”。
2、在命令提示符下,設(shè)置Go 程序使用的DBUSER和DBPASS環(huán)境變量。
在 Linux 或 Mac 上:
在 Windows 上:
3、在包含 main.go 的目錄中的命令行中,通過鍵入go run來運行代碼。
連接成功了!
接下來,您將查詢一些數(shù)據(jù)。