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

鍍金池/ 教程/ GO/ Go語(yǔ)言入門(mén)
Go panic錯(cuò)誤處理實(shí)例
Go命令行參數(shù)實(shí)例
Go可變參數(shù)的函數(shù)實(shí)例
Go通道同步實(shí)例
Go非阻塞通道操作實(shí)例
Go指針實(shí)例
Go數(shù)字解析實(shí)例
Go語(yǔ)言指針
Go超時(shí)(timeouts)實(shí)例
Go速率限制實(shí)例
Go信號(hào)實(shí)例
Go Base64編碼實(shí)例
Go計(jì)時(shí)器實(shí)例
Go命令行標(biāo)志實(shí)例
Go原子計(jì)數(shù)器實(shí)例
Go語(yǔ)言切片
Go隨機(jī)數(shù)實(shí)例
Go語(yǔ)言類型轉(zhuǎn)換
Go排序?qū)嵗?/span>
Go時(shí)間格式化/解析實(shí)例
Go URL解析實(shí)例
Go字符串函數(shù)實(shí)例
Go語(yǔ)言常量
Go for循環(huán)語(yǔ)句實(shí)例
Go函數(shù)多個(gè)返回值實(shí)例
Go切片實(shí)例
Go行過(guò)濾器實(shí)例
Go語(yǔ)言接口
Go語(yǔ)言數(shù)組
Go語(yǔ)言變量
Go字符串格式化實(shí)例
Go斷續(xù)器實(shí)例
Go if/else語(yǔ)句實(shí)例
Go通道緩沖實(shí)例
Go錯(cuò)誤實(shí)例
Go語(yǔ)言映射
Go執(zhí)行過(guò)程實(shí)例
Go函數(shù)實(shí)例
Go有狀態(tài)的goroutines實(shí)例
Go按自定義函數(shù)排序?qū)嵗?/span>
Go語(yǔ)言作用域規(guī)則
Go時(shí)代(Epoch)實(shí)例
Go變量實(shí)例
Go互斥體實(shí)例
Go語(yǔ)言范圍(range)
Go程序?qū)嵗?/span>
Go語(yǔ)言入門(mén)
Go通道路線實(shí)例
Go閉包(匿名函數(shù))實(shí)例
Go Select實(shí)例
Go通道范圍實(shí)例
Go集合函數(shù)實(shí)例
Hello World程序?qū)嵗?/span>
Go環(huán)境變量實(shí)例
Go語(yǔ)言運(yùn)算符
Go讀取文件實(shí)例
Go延遲(defer)實(shí)例
Go SHA1哈希實(shí)例
Go語(yǔ)言條件和決策
Go語(yǔ)言錯(cuò)誤處理
Go通道實(shí)例
Go指針實(shí)例
Go時(shí)間日期實(shí)例
Go語(yǔ)言字符串
Go語(yǔ)言循環(huán)
Go語(yǔ)言基礎(chǔ)語(yǔ)法
Go語(yǔ)言開(kāi)發(fā)環(huán)境安裝配置
Go常量實(shí)例
Go語(yǔ)言結(jié)構(gòu)體
Go寫(xiě)文件實(shí)例
Go正則表達(dá)式實(shí)例
Go JSON實(shí)例
Go語(yǔ)言教程
Go關(guān)閉通道實(shí)例
Go接口實(shí)例
Go語(yǔ)言遞歸
Go switch語(yǔ)句實(shí)例
Go函數(shù)遞歸實(shí)例
Go退出程序?qū)嵗?/span>
Go語(yǔ)言程序結(jié)構(gòu)
Go范圍實(shí)例
Go語(yǔ)言函數(shù)
Go工作池實(shí)例
Go語(yǔ)言數(shù)據(jù)類型

Go語(yǔ)言入門(mén)

在學(xué)習(xí)Go語(yǔ)言編程之前,我們需要安裝和配置好Go語(yǔ)言的開(kāi)發(fā)環(huán)境??梢赃x擇線上的編譯器:http://tour.golang.org/welcome/1 來(lái)直接執(zhí)行代碼。也可以在您自己的計(jì)算機(jī)上安裝開(kāi)發(fā)編譯環(huán)境。

Go本地環(huán)境設(shè)置

如果您愿意在本地環(huán)境安裝和配置Go編程語(yǔ)言,則需要在計(jì)算機(jī)上提供以下兩個(gè)軟件:

  • 文本編輯器
  • Go編譯器

文本編輯器

這是用于編寫(xiě)您的程序代碼。常見(jiàn)的幾個(gè)編輯器包括Windows記事本,OS編輯命令,Brief,Epsilon,EMACSvim(或vi)。

文本編輯器的名稱和版本可能因不同的操作系統(tǒng)而異。例如,記事本只能在Windows上使用,vim(或vi)可以在Windows以及Linux或UNIX上使用。

使用編輯器創(chuàng)建的文件稱為源文件,源文件中包含程序的源代碼。Go程序的源文件通常使用擴(kuò)展名“.go”來(lái)命名。

在開(kāi)始編程之前,確保您安裝好并熟練使用一個(gè)文本編輯器,并且有足夠的經(jīng)驗(yàn)來(lái)編寫(xiě)計(jì)算機(jī)程序代碼,將代碼保存在文件中,編譯并最終執(zhí)行它。

Go編譯器

在源文件中編寫(xiě)的源代碼是人類可讀的源程序。 它需要“編譯”變成機(jī)器語(yǔ)言,以便CPU可以根據(jù)給出的指令實(shí)際執(zhí)行程序。

這個(gè)Go編程語(yǔ)言編譯器用于將源代碼編譯成可執(zhí)行程序。這里假設(shè)您知道或了解編程語(yǔ)言編譯器的基本知識(shí)。

Go發(fā)行版本是FreeBSD(版本8及更高版本),Linux,Mac OS X(Snow Leopard及更高版本)和具有32位(386)和64位(amd64)x86處理器架構(gòu)的Windows操作系統(tǒng)的二進(jìn)制安裝版本 。

以下部分將演示如何在各種操作系統(tǒng)上安裝Go語(yǔ)言環(huán)境的二進(jìn)制分發(fā)包。

下載Go存檔文件

從鏈接【Go下載】中下載最新版本的Go可安裝的歸檔文件。在寫(xiě)本教程的時(shí)候,選擇的是go1.7.4.windows-amd64.msi并將下載到桌面上。

注:寫(xiě)本教程的時(shí),使用的電腦是:Windows 10 64bit 系統(tǒng)

如果操作系統(tǒng)不一樣,可選擇對(duì)應(yīng)版本下載安裝。

操作系統(tǒng) 存檔名稱
Windows go1.7.windows-amd64.msi
Linux go1.7.linux-amd64.tar.gz
Mac go1.7.4.darwin-amd64.pkg
FreeBSD go1.7.freebsd-amd64.tar.gz

在UNIX/Linux/Mac OS X和FreeBSD上安裝

將下載歸檔文件解壓縮到/usr/local目錄中,在/usr/local/go目錄創(chuàng)建一個(gè)Go樹(shù)。 例如:

tar -C /usr/local -xzf go1.7.4.linux-amd64.tar.gz

/usr/local/go/bin添加到PATH環(huán)境變量。

操作系統(tǒng) 輸出
Linux export PATH=$PATH:/usr/local/go/bin
Mac export PATH=$PATH:/usr/local/go/bin
FreeBSD export PATH=$PATH:/usr/local/go/bin

在Windows上安裝

使用MSI文件并按照提示安裝Go工具。 默認(rèn)情況下,安裝程序使用C:\Go目錄。安裝程序應(yīng)該在窗口的PATH環(huán)境變量中設(shè)置C:\Go\bin目錄。重新啟動(dòng)后,打開(kāi)的命令提示驗(yàn)證更改是否生效。

驗(yàn)證安裝結(jié)果

F:\worksp\golang中創(chuàng)建一個(gè)test.go的go文件。編寫(xiě)并保存以下代碼到 test.go 文件中。

package main

import "fmt"

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

現(xiàn)在運(yùn)行test.go查看結(jié)果并驗(yàn)證輸出結(jié)果如下:

F:\worksp\golang>go run test.go
Hello, World!

包的使用

每個(gè) Go 程序都是由包組成的。
程序運(yùn)行的入口是包 main
這個(gè)程序使用并導(dǎo)入了包 “fmt“ 和 “math/rand“ 。
按照慣例,包名與導(dǎo)入路徑的最后一個(gè)目錄一致。例如,”math/rand“ 包由 package rand 語(yǔ)句開(kāi)始。

注意:這個(gè)程序的運(yùn)行環(huán)境是確定性的,因此 rand.Intn 每次都會(huì)返回相同的數(shù)字。

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(10))
}

導(dǎo)入包

這個(gè)代碼用圓括號(hào)組合了導(dǎo)入,這是“打包”導(dǎo)入語(yǔ)句。

同樣可以編寫(xiě)多個(gè)導(dǎo)入語(yǔ)句,例如:

import "fmt"
import "math"

不過(guò)使用打包的導(dǎo)入語(yǔ)句是更好的形式。

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("Now you have %g problems.", math.Sqrt(7))
}

導(dǎo)出名稱

Go 中,首字母大寫(xiě)的名稱是被導(dǎo)出的。

在導(dǎo)入包之后,只能訪問(wèn)包所導(dǎo)出的名字,任何未導(dǎo)出的名字是不能被包外的代碼訪問(wèn)的。

FooFOO 都是被導(dǎo)出的名稱。名稱 foo 是不會(huì)被導(dǎo)出的。

執(zhí)行代碼,注意編譯器報(bào)的錯(cuò)誤。

然后將 math.pi 改名為 math.Pi 再試著執(zhí)行一下。

package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi)
}

函數(shù)

函數(shù)可以沒(méi)有參數(shù)或接受多個(gè)參數(shù)。
在這個(gè)例子中, add 接受兩個(gè) int 類型的參數(shù)。
注意類型在變量名之后 。

package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

當(dāng)兩個(gè)或多個(gè)連續(xù)的函數(shù)命名參數(shù)是同一類型,則除了最后一個(gè)類型之外,其他都可以省略。

在這個(gè)例子中 ,

x int, y int

可縮寫(xiě)為:

x, y int

函數(shù)多值返回

函數(shù)可以返回任意數(shù)量的返回值。
swap 函數(shù)返回了兩個(gè)字符串。

package main

import "fmt"

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

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

函數(shù)中命名返回值

Go 的返回值可以被命名,并且就像在函數(shù)體開(kāi)頭聲明的變量那樣使用。
返回值的名稱應(yīng)當(dāng)具有一定的意義,可以作為文檔使用。
沒(méi)有參數(shù)的 return 語(yǔ)句返回各個(gè)返回變量的當(dāng)前值。這種用法被稱作“裸”返回。
直接返回語(yǔ)句僅應(yīng)當(dāng)用在像下面這樣的短函數(shù)中。在長(zhǎng)的函數(shù)中它們會(huì)影響代碼的可讀性。

package main

import "fmt"

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}

變量

var 語(yǔ)句定義了一個(gè)變量的列表;跟函數(shù)的參數(shù)列表一樣,類型在后面。就像在這個(gè)例子中看到的一樣, var 語(yǔ)句可以定義在包或函數(shù)級(jí)別。

package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}

初始化變量

變量定義可以包含初始值,每個(gè)變量對(duì)應(yīng)一個(gè)。如果初始化是使用表達(dá)式,則可以省略類型;變量從初始值中獲得類型。

package main

import "fmt"

var i, j int = 1, 2

func main() {
    var c, python, java = true, false, "no!"
    fmt.Println(i, j, c, python, java)
}

短聲明變量

在函數(shù)中, := 簡(jiǎn)潔賦值語(yǔ)句在明確類型的地方,可以用于替代 var 定義。
函數(shù)外的每個(gè)語(yǔ)句都必須以關(guān)鍵字開(kāi)始( varfunc 、等等), :=結(jié)構(gòu)不能使用在函數(shù)外。

package main

import "fmt"

func main() {
    var i, j int = 1, 2
    k := 3
    c, python, java := true, false, "no!"

    fmt.Println(i, j, k, c, python, java)
}

基本數(shù)據(jù)類型

Go 的基本類型有:

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 的別名

rune // int32 的別名
     // 代表一個(gè)Unicode碼

float32 float64

complex64 complex128

這個(gè)例子演示了具有不同類型的變量。 同時(shí)與導(dǎo)入語(yǔ)句一樣,變量的定義“打包”在一個(gè)語(yǔ)法塊中。

int,uintuintptr 類型在32位的系統(tǒng)上一般是32位,而在64位系統(tǒng)上是64位。當(dāng)你需要使用一個(gè)整數(shù)類型時(shí),應(yīng)該首選 int,僅當(dāng)有特別的理由才使用定長(zhǎng)整數(shù)類型或者無(wú)符號(hào)整數(shù)類型。

package main

import (
    "fmt"
    "math/cmplx"
)

var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
    const f = "%T(%v)\n"
    fmt.Printf(f, ToBe, ToBe)
    fmt.Printf(f, MaxInt, MaxInt)
    fmt.Printf(f, z, z)
}

零值

變量在定義時(shí)沒(méi)有明確的初始化時(shí)會(huì)賦值為 零值 。

零值是:

數(shù)值類型為 0
布爾類型為 false ,
字符串為 “” (空字符串)。

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

類型轉(zhuǎn)換

表達(dá)式T(v) 將值 v 轉(zhuǎn)換為類型 T 。

一些關(guān)于數(shù)值的轉(zhuǎn)換:

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

或者,更加簡(jiǎn)單的形式:

i := 42
f := float64(i)
u := uint(f)

與 C 不同的是 Go 的在不同類型之間的項(xiàng)目賦值時(shí)需要顯式轉(zhuǎn)換。 試著移除例子中 float64int 的轉(zhuǎn)換看看會(huì)發(fā)生什么。

package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z)
}

類型推導(dǎo)

類型推導(dǎo)
在定義一個(gè)變量卻并不顯式指定其類型時(shí)(使用 := 語(yǔ)法或者 var =表達(dá)式語(yǔ)法), 變量的類型由(等號(hào))右側(cè)的值推導(dǎo)得出。

當(dāng)右值定義了類型時(shí),新變量的類型與其相同:

var i int
j := i // j 也是一個(gè) int

但是當(dāng)右邊包含了未指名類型的數(shù)字常量時(shí),新的變量就可能是 intfloat64complex128 。 這取決于常量的精度:

i := 42           // int
f := 3.142        // float64
g := 0.867 + 0.5i // complex128

嘗試修改演示代碼中 v 的初始值,并觀察這是如何影響其類型的。

package main

import "fmt"

func main() {
    v := 42 // change me!
    fmt.Printf("v is of type %T\n", v)
}

常量

常量的定義與變量類似,只不過(guò)使用 const 關(guān)鍵字。

常量可以是字符、字符串、布爾或數(shù)字類型的值。

常量不能使用 := 語(yǔ)法定義。

package main

import "fmt"

const Pi = 3.14

func main() {
    const World = "世界"
    fmt.Println("Hello", World)
    fmt.Println("Happy", Pi, "Day")

    const Truth = true
    fmt.Println("Go rules?", Truth)
}

數(shù)值常量

數(shù)值常量是高精度的值 。
一個(gè)未指定類型的常量由上下文來(lái)決定其類型。
也嘗試一下輸出 needInt(Big) 吧。
(int 可以存放最大64位的整數(shù),根據(jù)平臺(tái)不同有時(shí)會(huì)更少。)

package main

import "fmt"

const (
    Big   = 1 << 100
    Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}

func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
}

控制流

for

Go 只有一種循環(huán)結(jié)構(gòu) —— for 循環(huán)。

基本的 for 循環(huán)包含三個(gè)由分號(hào)分開(kāi)的組成部分:

初始化語(yǔ)句:在第一次循環(huán)執(zhí)行前被執(zhí)行
循環(huán)條件表達(dá)式:每輪迭代開(kāi)始前被求值
后置語(yǔ)句:每輪迭代后被執(zhí)行
初始化語(yǔ)句一般是一個(gè)短變量聲明,這里聲明的變量?jī)H在整個(gè) for 循環(huán)語(yǔ)句可見(jiàn)。

如果條件表達(dá)式的值變?yōu)?false,那么迭代將終止。

注意:不像 C,Java,或者 Javascript 等其他語(yǔ)言,for 語(yǔ)句的三個(gè)組成部分 并不需要用括號(hào)括起來(lái),但循環(huán)體必須用{ }括起來(lái)。

package main

import "fmt"

func main() {
    sum := 0
    for i := 0; i < 10; i++ {
        sum += i
    }
    fmt.Println(sum)
}

循環(huán)初始化語(yǔ)句和后置語(yǔ)句都是可選的,如下示例代碼所示 -

package main

import "fmt"

func main() {
    sum := 1
    for ; sum < 1000; {
        sum += sum
    }
    fmt.Println(sum)
}

for 是 Go 的 “while”

基于此可以省略分號(hào):C 的 while 在 Go 中叫做 for 。

package main

import "fmt"

func main() {
    sum := 1
    for sum < 1000 {
        sum += sum
    }
    fmt.Println(sum)
}

死循環(huán)

如果省略了循環(huán)條件,循環(huán)就不會(huì)結(jié)束,因此可以用更簡(jiǎn)潔地形式表達(dá)死循環(huán)。

package main

func main() {
    for {// 無(wú)退出條件,變成死循環(huán)
    }
}

if

就像 for 循環(huán)一樣,Go 的 if 語(yǔ)句也不要求用( ) 將條件括起來(lái),同時(shí),{ }還是必須有的。

package main

import (
    "fmt"
    "math"
)

func sqrt(x float64) string {
    if x < 0 {
        return sqrt(-x) + "i"
    }
    return fmt.Sprint(math.Sqrt(x))
}

func main() {
    fmt.Println(sqrt(2), sqrt(-4))
}

if 的便捷語(yǔ)句

for 語(yǔ)句一樣, if 語(yǔ)句可以在條件之前執(zhí)行一個(gè)簡(jiǎn)單語(yǔ)句。
由這個(gè)語(yǔ)句定義的變量的作用域僅在 if 范圍之內(nèi)。
(在最后的 return 語(yǔ)句處使用 v 看看。)

package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    }
    return lim
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}

if 和 else

if 的便捷語(yǔ)句定義的變量同樣可以在任何對(duì)應(yīng)的 else 塊中使用。
(提示:兩個(gè) pow 調(diào)用都在 main 調(diào)用 fmt.Println 前執(zhí)行完畢了。)

package main

import (
    "fmt"
    "math"
)

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    } else {
        fmt.Printf("%g >= %g\n", v, lim)
    }
    // 這里開(kāi)始就不能使用 v 了
    return lim
}

func main() {
    fmt.Println(
        pow(3, 2, 10),
        pow(3, 3, 20),
    )
}

switch語(yǔ)句

你可能已經(jīng)知道 switch 語(yǔ)句會(huì)長(zhǎng)什么樣了。
除非以 fallthrough 語(yǔ)句結(jié)束,否則分支會(huì)自動(dòng)終止。

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Print("Go runs on ")
    switch os := runtime.GOOS; os {
    case "darwin":
        fmt.Println("OS X.")
    case "linux":
        fmt.Println("Linux.")
    default:
        // freebsd, openbsd,
        // plan9, windows...
        fmt.Printf("%s.", os)
    }
}

switch 的執(zhí)行順序

switch 的條件從上到下的執(zhí)行,當(dāng)匹配成功的時(shí)候停止。

(例如,

switch i {
case 0:
case f():
}

當(dāng) i==0 時(shí)不會(huì)調(diào)用 f 。)

注意:Go playground 中的時(shí)間總是從 2009-11-10 23:00:00 UTC 開(kāi)始, 如何校驗(yàn)這個(gè)值作為一個(gè)練習(xí)留給讀者完成。

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("When's Saturday?")
    today := time.Now().Weekday()
    switch time.Saturday {
    case today + 0:
        fmt.Println("Today.")
    case today + 1:
        fmt.Println("Tomorrow.")
    case today + 2:
        fmt.Println("In two days.")
    default:
        fmt.Println("Too far away.")
    }
}

沒(méi)有條件的 switch

沒(méi)有條件的 switchswitch true 一樣。
這一構(gòu)造使得可以用更清晰的形式來(lái)編寫(xiě)長(zhǎng)的 if-then-else 鏈。

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good afternoon.")
    default:
        fmt.Println("Good evening.")
    }
}

defer語(yǔ)句

defer 語(yǔ)句會(huì)延遲函數(shù)的執(zhí)行直到上層函數(shù)返回。
延遲調(diào)用的參數(shù)會(huì)立刻生成,但是在上層函數(shù)返回前函數(shù)都不會(huì)被調(diào)用。

package main

import "fmt"

func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}

defer 棧

延遲的函數(shù)調(diào)用被壓入一個(gè)棧中。當(dāng)函數(shù)返回時(shí), 會(huì)按照后進(jìn)先出的順序調(diào)用被延遲的函數(shù)調(diào)用。

package main

import "fmt"

func main() {
    fmt.Println("counting")

    for i := 0; i < 10; i++ {
        defer fmt.Println(i)
    }

    fmt.Println("done")
}

指針

Go 具有指針。 指針保存了變量的內(nèi)存地址。

類型 *T 是指向類型 T的值的指針。其零值是 nil 。

var p *int

& 符號(hào)會(huì)生成一個(gè)指向其作用對(duì)象的指針。

i := 42
p = &i

*符號(hào)表示指針指向的底層的值。

fmt.Println(*p) // 通過(guò)指針 p 讀取 i
*p = 21         // 通過(guò)指針 p 設(shè)置 i

這也就是通常所說(shuō)的“間接引用”或“非直接引用”。
與 C 不同,Go 沒(méi)有指針運(yùn)算。

package main

import "fmt"

func main() {
    i, j := 42, 2701

    p := &i         // point to i
    fmt.Println(*p) // read i through the pointer
    *p = 21         // set i through the pointer
    fmt.Println(i)  // see the new value of i

    p = &j         // point to j
    *p = *p / 37   // divide j through the pointer
    fmt.Println(j) // see the new value of j
}

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

一個(gè)結(jié)構(gòu)體( struct )就是一個(gè)字段的集合。(而 type 的含義跟其字面意思相符。)

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
}

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

結(jié)構(gòu)體字段使用點(diǎn)號(hào)來(lái)訪問(wèn)。

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X)
}

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

結(jié)構(gòu)體字段可以通過(guò)結(jié)構(gòu)體指針來(lái)訪問(wèn)。
通過(guò)指針間接的訪問(wèn)是透明的。

package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    p := &v
    p.X = 1e9
    fmt.Println(v)
}

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

結(jié)構(gòu)體符文表示通過(guò)結(jié)構(gòu)體字段的值作為列表來(lái)新分配一個(gè)結(jié)構(gòu)體。
使用 Name: 語(yǔ)法可以僅列出部分字段。(字段名的順序無(wú)關(guān)。)
特殊的前綴 & 返回一個(gè)指向結(jié)構(gòu)體的指針。

package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    v1 = Vertex{1, 2}  // 類型為 Vertex
    v2 = Vertex{X: 1}  // Y:0 被省略
    v3 = Vertex{}      // X:0 和 Y:0
    p  = &Vertex{1, 2} // 類型為 *Vertex
)

func main() {
    fmt.Println(v1, p, v2, v3)
}

數(shù)組

類型 [n]T 是一個(gè)有 n 個(gè)類型為 T 的值的數(shù)組。

表達(dá)式

var a [10]int

定義變量 a 是一個(gè)有十個(gè)整數(shù)的數(shù)組。

數(shù)組的長(zhǎng)度是其類型的一部分,因此數(shù)組不能改變大小。這看起來(lái)是一個(gè)制約,但是請(qǐng)不要擔(dān)心; Go 提供了更加便利的方式來(lái)使用數(shù)組。

切片(slice)

一個(gè) slice 會(huì)指向一個(gè)序列的值,并且包含了長(zhǎng)度信息。

[]T 是一個(gè)元素類型為 T 的 切片(slice)。

len(s)返回 slice s的長(zhǎng)度。

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("s ==", s)

    for i := 0; i < len(s); i++ {
        fmt.Printf("s[%d] == %d\n", i, s[i])
    }
}

切片(slice)的切片

切片(slice)可以包含任意的類型,包括另一個(gè) slice。

package main

import (
    "fmt"
    "strings"
)

func main() {
    // Create a tic-tac-toe board.
    game := [][]string{
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
        []string{"_", "_", "_"},
    }

    // The players take turns.
    game[0][0] = "X"
    game[2][2] = "O"
    game[2][0] = "X"
    game[1][0] = "O"
    game[0][2] = "X"

    printBoard(game)
}

func printBoard(s [][]string) {
    for i := 0; i < len(s); i++ {
        fmt.Printf("%s\n", strings.Join(s[i], " "))
    }
}

對(duì) slice 切片

slice 可以重新切片,創(chuàng)建一個(gè)新的 slice 值指向相同的數(shù)組。

表達(dá)式

s[lo:hi]

表示從 lohi-1slice 元素,含前端,不包含后端。因此

s[lo:lo]

是空的,而

s[lo:lo+1]

有一個(gè)元素。

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("s ==", s)
    fmt.Println("s[1:4] ==", s[1:4])

    // 省略下標(biāo)代表從 0 開(kāi)始
    fmt.Println("s[:3] ==", s[:3])

    // 省略上標(biāo)代表到 len(s) 結(jié)束
    fmt.Println("s[4:] ==", s[4:])
}

構(gòu)造 slice

slice 由函數(shù) make 創(chuàng)建。這會(huì)分配一個(gè)全是零值的數(shù)組并且返回一個(gè) slice 指向這個(gè)數(shù)組:

a := make([]int, 5)  // len(a)=5

為了指定容量,可傳遞第三個(gè)參數(shù)到 make

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4

參考以下示例代碼 -

package main

import "fmt"

func main() {
    a := make([]int, 5)
    printSlice("a", a)
    b := make([]int, 0, 5)
    printSlice("b", b)
    c := b[:2]
    printSlice("c", c)
    d := c[2:5]
    printSlice("d", d)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

nil slice

slice 的零值是 nil 。

一個(gè) nilslice 的長(zhǎng)度和容量是 0。

package main

import "fmt"

func main() {
    var z []int
    fmt.Println(z, len(z), cap(z))
    if z == nil {
        fmt.Println("nil!")
    }
}

向 slice 添加元素

slice 的末尾添加元素是一種常見(jiàn)的操作,因此 Go 提供了一個(gè)內(nèi)建函數(shù) append 。 內(nèi)建函數(shù)的文檔對(duì) append 有詳細(xì)介紹。

func append(s []T, vs ...T) []T

append 的第一個(gè)參數(shù) s 是一個(gè)元素類型為 Tslice ,其余類型為 T 的值將會(huì)附加到該 slice 的末尾。

append 的結(jié)果是一個(gè)包含原 slice 所有元素加上新添加的元素的 slice

如果 s 的底層數(shù)組太小,而不能容納所有值時(shí),會(huì)分配一個(gè)更大的數(shù)組。 返回的 slice 會(huì)指向這個(gè)新分配的數(shù)組。

package main

import "fmt"

func main() {
    var a []int
    printSlice("a", a)

    // append works on nil slices.
    a = append(a, 0)
    printSlice("a", a)

    // the slice grows as needed.
    a = append(a, 1)
    printSlice("a", a)

    // we can add more than one element at a time.
    a = append(a, 2, 3, 4)
    printSlice("a", a)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

范圍(range)

for 循環(huán)的 range 格式可以對(duì) slice 或者 map 進(jìn)行迭代循環(huán)。

當(dāng)使用 for 循環(huán)遍歷一個(gè) slice 時(shí),每次迭代 range 將返回兩個(gè)值。 第一個(gè)是當(dāng)前下標(biāo)(序號(hào)),第二個(gè)是該下標(biāo)所對(duì)應(yīng)元素的一個(gè)拷貝。

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
    for i, v := range pow {
        fmt.Printf("2**%d = %d\n", i, v)
    }
}

可以通過(guò)賦值給 _ 來(lái)忽略序號(hào)和值。

如果只需要索引值,去掉 “ , value ” 的部分即可。

package main

import "fmt"

func main() {
    pow := make([]int, 10)
    for i := range pow {
        pow[i] = 1 << uint(i)
    }
    for _, value := range pow {
        fmt.Printf("%d\n", value)
    }
}