實戰(zhàn)系列:(四)一天搞定Go語言

寫在前面

? ? ? ?本文是Go語言的快速入門教程,適合于具有一定C語言或者Java語言基礎(chǔ)的開發(fā)人員,如果您是一位Go語言的熟練使用者,請繞行!像作者這個年紀(jì)的老碼農(nóng)通常都是從Pascal語言或者c語言開始學(xué)習(xí)計算機技術(shù)的,所以學(xué)起Go語言生來就有一種似曾相識的感覺,還是蠻輕松的!
? ? ? ?當(dāng)然,目前筆者也只能算是了解Go語言而已,還不能算熟悉,離精通那就差的更遠(yuǎn)了!說到這個計算機相關(guān)技術(shù)的掌握程度,又得發(fā)點牢騷,了解,熟悉,精通,這是不同的水平層次的表現(xiàn)。作為一個保守的,略帶謙虛氣質(zhì)的老碼農(nóng),我從來不敢說自己精通某某技術(shù),某某語言,頂多敢在簡歷里面寫上熟練掌握和使用某某語言、技術(shù)而已。如若讓我看到誰的簡歷里面敢寫精通某某語言、某某技術(shù),碰巧又遇到我來面試,那他肯定死的很慘。我會面的他無地自容、信心喪失、立馬尋死!當(dāng)然大神除外,大神級的人物也輪不到我來面試,呵呵!

一、Go語言簡介

? ? ? ?咱們書歸正傳,來一起學(xué)習(xí)一下Go語言。Go的全稱是GoLang,“夠浪”你就來學(xué)Go語言,呵呵!筆者之前沒有Go語言的任何經(jīng)驗,也是臨危受命,被逼無奈,開始了“夠浪”的學(xué)習(xí)和開發(fā)歷程。


地鼠logo

? ? ? ?這個小地鼠不一般,它是Go語言的吉祥物,蠻可愛的!就和Go一樣,簡潔明了。
? ? ? ?Go是一個開源的編程語言,它能夠構(gòu)造簡單、可靠且高效的軟件。Go是從2007年末由Google公司的Robert Griesemer, Rob Pike, Ken Thompson主持開發(fā)的,并最終于2009年11月開源,在2012年早些時候發(fā)布了Go 1穩(wěn)定版本?,F(xiàn)在Go的開發(fā)已經(jīng)是完全開放的,并且擁有一個活躍的社區(qū)。

Go語言有如下特點:

  • 簡潔、快速、安全
  • 并行、有趣、開源
  • 內(nèi)存管理、數(shù)組安全、編譯迅速

? ? ? ?下面我們就一起來開啟“夠浪”的快速學(xué)習(xí)之旅。

二、Go語言基礎(chǔ)

? ? ? ?計算機軟件經(jīng)歷了數(shù)十年的發(fā)展,形成了多種學(xué)術(shù)流派,有面向過程編程、面向?qū)ο缶幊獭⒑瘮?shù)式編程、面向消息編程等,這些思想究竟孰優(yōu)孰劣,眾說紛紜,作者不予評價。
? ? ? ?Go語言對這些思想均有所吸收。例如,Go語言接受了函數(shù)式編程的一些想法,支持匿名函數(shù)與閉包。再如,Go語言接受了以Erlang語言為代表的面向消息編程思想,支持goroutine和通道,并推薦使用消息而不是共享內(nèi)存來進(jìn)行并發(fā)編程。總體來說,Go語言是一個非?,F(xiàn)代化的語言,精小但非常強大。
? ? ? ?Go語言是谷歌2009發(fā)布的第二款開源編程語言。Go語言專門針對多處理器系統(tǒng)應(yīng)用程序的編程進(jìn)行了優(yōu)化,使用Go編譯的程序可以媲美C或C++代碼的速度,而且更加安全、支持并行進(jìn)程。
Go 語言的主要特性如下:

  • 自動垃圾回收
  • 更豐富的內(nèi)置類型
  • 函數(shù)多返回值
  • 錯誤處理
  • 匿名函數(shù)和閉包
  • 類型和接口
  • 并發(fā)編程
  • 反射
  • 語言交互性

? ? ? ?說了這么多,趕緊讓大家來親身體會一下吧!因為Go語言在語法上很大程度的類似C語言,故此本文不會面面俱到的講解Go的語法,只會著重指出與C不同的地方以及Go自身有特色的內(nèi)容。
? ? ? ?第一個Go程序,仍然從hello world開始!

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

? ? ? ?也像Java也像C,有package來做包管理,import來導(dǎo)入類庫(包),main是入口函數(shù)。

  1. 第一行代碼 package main 定義了包名。package main表示一個可獨立執(zhí)行的程序,每個Go應(yīng)用程序都包含一個名為main的包;
  2. import "fmt" 告訴Go編譯器這個程序需要使用fmt包;
  3. func main() 是程序開始執(zhí)行的函數(shù),即入口函數(shù);
  4. 當(dāng)標(biāo)識符(包括常量、變量、類型、函數(shù)名、結(jié)構(gòu)字段等)以一個大寫字母開頭,那么使用這種形式的標(biāo)識符對象就可以被外部包的代碼所使用,這被稱為導(dǎo)出(類似OOP中的public);標(biāo)識符如果以小寫字母開頭,則對包外是不可見的,但是他們在整個包的內(nèi)部是可見并且可用的(類似于OOP中的protected )。

? ? ? ?在Go程序中,一行代表一個語句結(jié)束。每個語句不需要以分號;結(jié)尾,因為這些工作都將由Go編譯器自動完成。如果你打算將多個語句寫在同一行,它們則必須使用;人為區(qū)分,但在實際開發(fā)中并不鼓勵這種做法。
? ? ? ?下面就從Go的語法方面介紹Go的特點,主要集中在區(qū)別于C語言的部分。

標(biāo)識符

? ? ? ?Go語言標(biāo)識符、關(guān)鍵字、保留字、注釋與C語言類似,不再贅述。

變量聲明

? ? ? ?Go使用var來聲明變量,變量類型放在后面,例如:

var age int

一次可以聲明多個變量,例如:

var a, b int = 1, 2

? ? ? ?聲明變量可以省略var,使用:=聲明符(初始化聲明)。但要注意省略 var, := 左側(cè)如果沒有聲明新的變量,就產(chǎn)生編譯錯誤。例如:

var intValue int 
intValue := 1 //這時候會產(chǎn)生編譯錯誤
intValue, intValue1 := 1, 2 //此時不會產(chǎn)生編譯錯誤,因為有新的變量聲明, := 是一個聲明語句

可以將

var f string = "test" 

簡寫為

 f := "test"

? ? ? ?因為Go可以根據(jù)值自行判定變量類型,可以在變量初始化時省略變量的類型而由系統(tǒng)自動推斷。

指針

? ? ? ?與c語言類似,Go也使用指針,&符號返回變量的地址,*符號聲明指針變量。

條件判斷語句

? ? ? ?Go的條件判斷語句同樣有if else和switch,if語句沒有什么特別之處,switch語句倒是有很大不同。
? ? ? ?Go 編程語言中 if 語句的語法如下:

if 布爾表達(dá)式 {
}

if 布爾表達(dá)式 {
} else {
}

? ? ? ?Go 編程語言中 switch 語句的語法如下:

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}

? ? ? ?變量var1可以是任何類型,而val1和val2則可以是同類型的任意值。類型不被局限于常量或整數(shù),但必須是相同的類型;或者最終結(jié)果為相同類型的表達(dá)式。也可以同時測試多個可能符合條件的值,使用逗號分割。不同的case之間不需要使用break分隔。
? ? ? ?switch語句還有一個fallthrough特性。使用fallthrough會強制執(zhí)行后面的一條case語句,fallthrough不會判斷下一條 case的表達(dá)式結(jié)果是否為true,直接執(zhí)行。
? ? ? ?Go語言還有一個特殊的控制結(jié)構(gòu),select語句,與switch語句有些類似。每個case 必須是一個通信操作,要么是發(fā)送要么是接收。select會隨機執(zhí)行一個可運行的case。如果沒有case可運行,它將阻塞,直到有case可運行。
? ? ? ?Go 編程語言中 select 語句的語法如下:

select {
    case 通信操作 :
       執(zhí)行語句;      
    case 通信操作  :
       執(zhí)行語句; 
    ...
    default : 
       執(zhí)行語句;
}
Range

? ? ? ?在講循環(huán)語句之前先說一下Range關(guān)鍵字。Go語言中range關(guān)鍵字用于for循環(huán)中迭代數(shù)組(array)、切片(slice)、通道(channel)或集合(map)的元素。在數(shù)組和切片中它返回元素的索引和索引對應(yīng)的值,在集合中返回key-value對的key值。

循環(huán)語句

? ? ? ?Go 語言沒有while和do...while語法,可以通過for 循環(huán)來實現(xiàn)其使用效果。Go語言的For循環(huán)有3種形式:

  • 和 C 語言的 for 一樣:for init; condition; post { }
  • 和 C 語言的 while 一樣:for condition { }
  • 和 C 語言的 for(;;) 一樣:for { }

? ? ? ?循環(huán)控制語句有break, continue, goto。goto語句通常與條件語句配合使用??捎脕韺崿F(xiàn)條件轉(zhuǎn)移,構(gòu)成循環(huán),跳出循環(huán)體等功能。但是,在結(jié)構(gòu)化程序設(shè)計中一般不主張使用goto語句, 以免造成程序流程的混亂,使理解和調(diào)試程序都產(chǎn)生困難。
? ? ? ?for循環(huán)的range格式可以對slice、map、數(shù)組、字符串等進(jìn)行迭代循環(huán)。

for key, value := range aMap {
    newMap[key] = value
}
Go的函數(shù)

? ? ? ?Go語言函數(shù)定義格式如下:

func function_name( [parameter list] ) [return_types] {
    函數(shù)體
}

? ? ? ?Go函數(shù)可以有多個返回值,這是Go的一大特點。如下例所示:

package main

import "fmt"

func swap(x, y string) (string, string) {
   return y, x
}

func main() {
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)
}

? ? ? ?Go與C一樣,參數(shù)傳遞方式有值傳遞和引用傳遞。默認(rèn)情況下,Go語言使用的是值傳遞,即在調(diào)用過程中不會影響到實際參數(shù)。
? ? ? ?Go的函數(shù)定義后可作為另外一個函數(shù)的實參數(shù)傳入,Go語言可以很靈活的創(chuàng)建函數(shù),并作為另外一個函數(shù)的實參。函數(shù)作為參數(shù)傳遞,實現(xiàn)回調(diào),如下例所示:

package main
import "fmt"

// 聲明一個函數(shù)類型
type cb func(int) int

func main() {
    testCallBack(1, callBack)
    testCallBack(2, func(x int) int {
        fmt.Printf("call back,x:%d\n", x)
        return x
    })
}

func testCallBack(x int, f cb) {
    f(x)
}

func callBack(x int) int {
    fmt.Printf("call back,x:%d\n", x)
    return x
}

? ? ? ?Go語言支持匿名函數(shù),可作為閉包。匿名函數(shù)是一個"內(nèi)聯(lián)"語句或表達(dá)式。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內(nèi)的變量,不必聲明。
? ? ? ?Go語言中同時有函數(shù)和方法。一個方法就是一個包含了接受者的函數(shù),接受者可以是命名類型或者結(jié)構(gòu)體類型的一個值或者是一個指針。所有給定類型的方法屬于該類型的方法集。語法格式如下:

func (variable_name variable_data_type) function_name() [return_type] {
   /* 方法體 */
}
變量作用域

? ? ? ?Go 語言中變量可以在三個地方聲明:

  • 函數(shù)內(nèi)定義的變量稱為局部變量;
  • 在函數(shù)體外聲明的變量稱之為全局變量,全局變量可以在整個包甚至外部包(被導(dǎo)出后)使用;
  • 函數(shù)定義中的變量稱為形式參數(shù);

? ? ? ?Go 語言程序中全局變量與局部變量名稱可以相同,但是函數(shù)內(nèi)的局部變量會被優(yōu)先考慮。

數(shù)組

? ? ? ?Go語言數(shù)組聲明需要指定元素類型及元素個數(shù),語法格式如下:

var variable_name [SIZE] variable_type

初始化數(shù)組:

var balance = [6]float32{100.0, 2.1, 3.4, 7.6, 30.2, 8.9}
切片

? ? ? ?Go語言切片實際上就是動態(tài)數(shù)組。與數(shù)組相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。
? ? ? ?你可以聲明一個未指定大小的數(shù)組來定義切片:

var sliceA []type

切片不需要說明長度?;蚴褂胢ake()函數(shù)來創(chuàng)建切片。也可以指定容量,其中capacity為可選參數(shù)。

make([]T, length, capacity)

切片提供了計算容量的方法cap()可以測量切片最長可以達(dá)到多少。一個切片在未初始化之前默認(rèn)為nil,長度為0。

空值

? ? ? ?Go語言的空值為nil,在概念上和其它語言的null、None、NULL一樣。

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

? ? ? ?Go語言的結(jié)構(gòu)體與C語言類似,結(jié)構(gòu)體定義需要使用 type 和 struct 語句。struct 語句定義一個新的數(shù)據(jù)類型,結(jié)構(gòu)體有中有一個或多個成員。type 語句設(shè)定了結(jié)構(gòu)體的名稱。結(jié)構(gòu)體的格式如下:

type struct_variable_type struct {
   member definition;
   member definition;
   ...
   member definition;
}

? ? ? ?如果要訪問結(jié)構(gòu)體成員,需要使用點號"."操作符,使用結(jié)構(gòu)體指針訪問結(jié)構(gòu)體成員,同樣使用 "." 操作符。

Map

? ? ? ?Key/value的鍵值對,可以使用內(nèi)建函數(shù) make ,也可以使用map關(guān)鍵字來定義Map:

/* 聲明變量,默認(rèn) map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函數(shù) */
map_variable := make(map[key_data_type]value_data_type)
類型轉(zhuǎn)換

? ? ? ?類型轉(zhuǎn)換用于將一種數(shù)據(jù)類型的變量轉(zhuǎn)換為另外一種類型的變量。Go語言類型轉(zhuǎn)換基本格式如下:

type_name(expression)

type_name為類型,expression為表達(dá)式。

Interface

? ? ? ?Go語言提供了另外一種數(shù)據(jù)類型即接口,它把所有的具有共性的方法定義在一起,任何其他類型只要實現(xiàn)了這些方法就是實現(xiàn)了這個接口。

type interface_name interface {
   method1 [return_type]
   method2 [return_type]
   method3 [return_type]
   ...
   methodN [return_type]
}
錯誤處理

? ? ? ?Go語言通過內(nèi)置的錯誤接口提供了非常簡單的錯誤處理機制。error類型是一個接口類型,這是它的定義:

type error interface {
    Error() string
}

? ? ? ?我們可以在編碼中通過實現(xiàn)error接口類型來生成錯誤信息。函數(shù)通常在最后的返回值中返回錯誤信息,使用errors.New 可返回一個錯誤信息。
? ? ? ?此外,panic與recover是Go的兩個內(nèi)置函數(shù),這兩個內(nèi)置函數(shù)用于處理Go運行時的錯誤,panic用于主動拋出錯誤,recover用來捕獲panic拋出的錯誤。還有一個defer語句,其目的類似于Java的finally,在當(dāng)前函數(shù)的末尾執(zhí)行一些清理代碼,而不管此函數(shù)如何退出。defer的有趣之處在于它跟代碼塊沒有聯(lián)系,可以隨時出現(xiàn)。

并發(fā)

? ? ? ?Go語言支持并發(fā),我們只需要通過go關(guān)鍵字來開啟goroutine即可。goroutine是輕量級線程,goroutine的調(diào)度是由Golang運行時進(jìn)行管理的。goroutine語法格式:

go 函數(shù)名( 參數(shù)列表 )

? ? ? ?同一個程序中的所有g(shù)oroutine共享同一個地址空間。goroutine是golang中在語言級別實現(xiàn)的輕量級線程,僅僅利用go就能立刻起一個新線程。

通道

? ? ? ?通道(channel)是用來傳遞數(shù)據(jù)的一個數(shù)據(jù)結(jié)構(gòu)。通道可用于兩個goroutine之間通過傳遞一個指定類型的值來同步運行和通訊。操作符<- 用于指定通道的方向,發(fā)送或接收。如果未指定方向,則為雙向通道。

ch <- v    // 把v發(fā)送到通道ch
v := <-ch  // 從ch接收數(shù)據(jù), 并把值賦給v

? ? ? ?聲明一個通道很簡單,我們使用chan關(guān)鍵字即可,通道在使用前必須先創(chuàng)建。

ch := make(chan int)

三、Web框架

? ? ? ?互聯(lián)網(wǎng)時代就得學(xué)習(xí)一下Web框架。Gin是一個go寫的web框架,具有高性能的優(yōu)點。官方地址:https://github.com/gin-gonic/gin
1、下載并安裝
$ go get -u github.com/gin-gonic/gin

2、在代碼中導(dǎo)入它
import "github.com/gin-gonic/gin"

使用gin需要Go的版本號為1.6或更高。

? ? ? ?下面我們就通過一個簡單的例子來快速入門Gin。

package main

import "github.com/gin-gonic/gin"

func main() {
    router := gin.Default()
    router.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    router.Run() // listening on 0.0.0.0:8080
}

運行這段代碼并在瀏覽器中訪問 http://localhost:8080。

HTTP方法

? ? ? ?可以使用 GET, POST, PUT, PATCH, DELETE, OPTIONS等方法。

參數(shù)獲取

獲取路徑中的參數(shù):

router.GET("/user/:name", func(c *gin.Context) {
    name := c.Param("name")
    c.String(http.StatusOK, "Hello %s", name)
})

獲取Get參數(shù):

firstname := c.DefaultQuery("firstname", "Guest")
lastname := c.Query("lastname")

獲取Post參數(shù):

message := c.PostForm("message")
nick := c.DefaultPostForm("nick", "anonymous")
路由分組

使用Group方法進(jìn)行路由分組:

v1 := router.Group("/v1")
v2 := router.Group("/v2")
使用中間件

可以使用在全局上,也可以使用在分組上。

模型綁定和驗證

? ? ? ?若要將請求主體綁定到結(jié)構(gòu)體中,請使用模型綁定,目前支持JSON、XML、YAML和標(biāo)準(zhǔn)表單值(foo=bar&boo=baz)的綁定。需要在綁定的字段上設(shè)置tag,比如,綁定格式為json,需要這樣設(shè)置 json:"fieldname" 。當(dāng)我們使用綁定方法時,Gin會根據(jù)Content-Type推斷出使用哪種綁定器,如果你確定你綁定的是什么,你可以使用MustBindWith或者BindingWith。下面以綁定JSON類型為例:

// 綁定為json
type Login struct {
    User     string `json:"user" binding:"required"`
    Password string `json:"password" binding:"required"`
}

func main() {
    router := gin.Default()

    // Example for binding JSON ({"user": "test", "password": "123"})
    router.POST("/login", func(c *gin.Context) {
        var json Login
        if err := c.ShouldBindJSON(&json); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        
        if json.User != "test" || json.Password != "123" {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            return
        } 
        
        c.JSON(http.StatusOK, gin.H{"status": "Login successfully!"})
    })
}

? ? ? ?關(guān)于Gin就講這么多,夠用了,想了解更加詳細(xì)的內(nèi)容,請訪問Gin的官方網(wǎng)站。

四、ORM工具

? ? ? ?有了Web框架,還得有ORM才算配齊。xorm是一個Go語言O(shè)RM庫. 通過它可以使數(shù)據(jù)庫操作非常簡便。xorm的特性如下:

  • 支持Struct和數(shù)據(jù)庫表之間的靈活映射,并支持自動同步表結(jié)構(gòu)
  • 事務(wù)支持
  • 支持原始SQL語句和ORM操作的混合執(zhí)行
  • 使用連寫來簡化調(diào)用
  • 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函數(shù)和結(jié)構(gòu)體等方式作為條件
  • 支持級聯(lián)加載Struct
  • 支持LRU緩存(支持memory, memcache, leveldb, redis緩存Store) 和 Redis緩存
  • 支持反轉(zhuǎn),即根據(jù)數(shù)據(jù)庫自動生成xorm的結(jié)構(gòu)體
  • 支持事件
  • 支持created, updated, deleted和version記錄版本(即樂觀鎖)
    ? ? ? ?下面還是通過一個簡單的例子來入門xorm,使用Mysql數(shù)據(jù)庫。
//匿名導(dǎo)入包:只導(dǎo)入包,而不使用任何包內(nèi)的結(jié)構(gòu)和類型,也不調(diào)用包內(nèi)的任何函數(shù)
import _ "github.com/go-sql-driver/mysql" 

type Account struct {
    Id      int64
    Name    string `xorm:"unique"`
    Balance float64
    Version int `xorm:"version"`
}

var x *xorm.Engine
x, err := xorm.NewEngine("mysql", "root:123456@/admin?charset=utf8")
獲取數(shù)據(jù)

? ? ? ?查詢單條數(shù)據(jù)使用Get方法,在調(diào)用Get方法時需要傳入一個對應(yīng)結(jié)構(gòu)體的指針,同時結(jié)構(gòu)體中的非空field自動成為查詢的條件和前面的方法條件組合在一起查詢。
根據(jù)Id來獲得單條數(shù)據(jù):

a:=&Account{}
has, err := x.Id(id).Get(a)

根據(jù)where獲取單條數(shù)據(jù):

a := new(Account)
has, err := x.Where("name=?", "admin").Get(a)

返回的結(jié)果為兩個參數(shù),一個has(bool類型)為該條記錄是否存在,第二個參數(shù)err為是否有錯誤。不管err是否為nil,has都有可能為true或者false。

批量獲取數(shù)據(jù)

err = x.Desc("balance").Find(&as)

Find方法的第一個參數(shù)為slice的指針或Map指針,即為查詢后返回的結(jié)果,第二個參數(shù)可選,為查詢的條件struct的指針。

增刪改操作

增加操作:

_, err := x.Insert(&Account{Name: name, Balance: balance})

刪除操作:

_, err := x.Delete(&Account{Id: id})

? ? ? ?方法 Delete 接受參數(shù)后,會自動根據(jù)傳進(jìn)去的值進(jìn)行查找,然后刪除。比如此處,我們指定了 Account 的 ID 字段,那么就會刪除 ID 字段值與我們所賦值相同的記錄;如果您只對 Name 字段賦值,那么 xorm 就會去查找 Name 字段值匹配的記錄。如果多個字段同時賦值,
則是多個條件同時滿足的記錄才會被刪除。

更新操作:

a := &Account{Id:1}
has, err := x.Get(a)

a.Balance += 1
_, err := x.Update(a)
事務(wù)
// 創(chuàng)建 Session 對象
sess := x.NewSession()
defer sess.Close()// 開啟事務(wù)
if err = sess.Begin(); err != nil {
    return err
}

if _, err = sess.Update(a1); err != nil {    // 發(fā)生錯誤時進(jìn)行回滾
    sess.Rollback()    
    return err
} 

// 完成事務(wù)
return sess.Commit()

五、總結(jié)

? ? ? ?實際上筆者也是一名Go的新手,該部分記錄一下筆者在使用Go的過程中的一些經(jīng)驗總結(jié)以及踩過的坑。

  1. {不能單獨放在一行;
  2. Go語言的字符串連接可以通過+實現(xiàn);
  3. 空標(biāo)識符“_”是一個占位符,用于在賦值操作的時候?qū)⒛硞€值賦值給空標(biāo)識符,從而達(dá)到丟棄該值的目的??諛?biāo)識符不是一個新的變量,因此將它用于:=操作符的時候,必須同時為至少另一個值賦值;
  4. 如果在相同的代碼塊中,我們不可以再次對于相同名稱的變量使用初始化聲明:=,編譯器會提示錯誤 no new variables on left side of :=,但是=賦值是可以的,因為這是給相同的變量賦予一個新的值;
  5. 如果你在定義變量a之前使用它,則會得到編譯錯誤 undefined: a;
  6. 如果你聲明了一個局部變量卻沒有在相同的代碼塊中使用它,同樣會得到編譯錯誤:xx declared and not used;
  7. 單純地給變量(如:a)賦值是不夠的,這個值必須被使用,但是全局變量是允許聲明但不使用的;
  8. Go沒有三目運算符,所以不支持 ?: 形式的條件判斷;
  9. int轉(zhuǎn)換為String類型時,不能用String()進(jìn)行類型轉(zhuǎn)換,而應(yīng)該使用 strconv.Itoa();
Package strconv implements conversions to and from string representations of basic data types.
Itoa is equivalent to FormatInt(int64(i), 10)

如果使用string()的話,將返回UTF-8編碼值。

string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. 
A string may be empty, but not nil. Values of string type are immutable.

六、學(xué)習(xí)資源

  1. 菜鳥教程 - https://www.runoob.com/go/go-tutorial.html
  2. Gin框架中文文檔 - http://www.itdecent.cn/p/98965b3ff638/
  3. golang-xorm庫快速學(xué)習(xí) - https://www.imooc.com/article/46419

? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?2019年8月13日 星期二 于青島

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容