1. 程式人生 > 其它 >Go 語言官方教程-學習指南-快速入門

Go 語言官方教程-學習指南-快速入門

bilibili事件發生後,忽然意識到這麼高大上的bilibili竟然是用Go(golang)語言寫的。忍不住我也要開始學這門有趣的語言。

其實Go官方是有非常好的中文版官方教程的,尊重版權[1](Golang Doc)。

這裡我與大家分享出來一些文件的重點,首先是基礎篇的內容,學完就能正式入門Go了,希望大家能happy。(我邊學邊更新~)


每個 Go 程式都是由包構成的。

程式從main包開始執行。

本程式通過匯入路徑"fmt""math/rand"來使用這兩個包。

按照約定,包名與匯入路徑的最後一個元素一致。例如,"math/rand"包中的原始碼均以package rand語句開始。

*注意:* 此程式的執行環境是固定的,因此rand.Intn總是會返回相同的數字。 (要得到不同的數字,需為生成器提供不同的種子數,參見rand.Seed。 練習場中的時間為常量,因此你需要用其它的值作為種子數。)

package main

import (
	"fmt"
	"math/rand"
)

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

匯入

此程式碼用圓括號組合了匯入,這是“分組”形式的匯入語句。

當然你也可以編寫多個匯入語句,例如:

import "fmt"
import "math"

不過使用分組匯入語句是更好的形式。

package main

import (
	"fmt"
	"math"
)

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

匯出名

在 Go 中,如果一個名字以大寫字母開頭,那麼它就是已匯出的。例如,Pizza就是個已匯出名,Pi也同樣,它匯出自math包。

pizzapi並未以大寫字母開頭,所以它們是未匯出的。

在匯入一個包時,你只能引用其中已匯出的名字。任何“未匯出”的名字在該包外均無法訪問。

執行程式碼,觀察錯誤輸出。

然後將math.pi

改名為math.Pi再試著執行一次。

package main

import (
	"fmt"
	"math"
)

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

函式

函式可以沒有引數或接受多個引數。

在本例中,add接受兩個int型別的引數。

注意型別在變數名之後

(參考這篇關於 Go 語法宣告的文章瞭解這種型別宣告形式出現的原因。)

package main

import "fmt"

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

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

函式(續)

當連續兩個或多個函式的已命名形參型別相同時,除最後一個型別以外,其它都可以省略。

在本例中,

x int, y int

被縮寫為

x, y int

package main

import "fmt"

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

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

多值返回

函式可以返回任意數量的返回值。

swap函式返回了兩個字串。

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)
}

命名返回值

Go 的返回值可被命名,它們會被視作定義在函式頂部的變數。

返回值的名稱應當具有一定的意義,它可以作為文件使用。

沒有引數的return語句返回已命名的返回值。也就是直接返回。

直接返回語句應當僅用在下面這樣的短函式中。在長的函式中它們會影響程式碼的可讀性。

package main

import "fmt"

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

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

變數

var語句用於宣告一個變數列表,跟函式的引數列表一樣,型別在最後。

就像在這個例子中看到的一樣,var語句可以出現在包或函式級別。

package main

import "fmt"

var c, python, java bool

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

變數的初始化

變數宣告可以包含初始值,每個變數對應一個。

如果初始化值已存在,則可以省略型別;變數會從初始值中獲得型別。

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)
}

短變數宣告

在函式中,簡潔賦值語句:=可在型別明確的地方代替var宣告。

函式外的每個語句都必須以關鍵字開始(var,func等等),因此:=結構不能在手機遊戲賬號交易地圖函式外使用。

package main

import "fmt"

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

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

基本型別

Go 的基本型別有

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 的別名

rune // int32 的別名
    // 表示一個 Unicode 碼點

float32 float64

complex64 complex128

本例展示了幾種型別的變數。 同匯入語句一樣,變數宣告也可以“分組”成一個語法塊。

int,uintuintptr在 32 位系統上通常為 32 位寬,在 64 位系統上則為 64 位寬。 當你需要一個整數值時應使用int型別,除非你有特殊的理由使用固定大小或無符號的整數型別。

package main

import (
	"fmt"
	"math/cmplx"
)

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

func main() {
	fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
	fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
	fmt.Printf("Type: %T Value: %v\n", z, z)
}

零值

沒有明確初始值的變數宣告會被賦予它們的零值

零值是:

  • 數值型別為
  • 布林型別為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)
}

型別轉換

表示式T(v)將值v轉換為型別T

一些關於數值的轉換:

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

或者,更加簡單的形式:

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

與 C 不同的是,Go 在不同型別的項之間賦值時需要顯式轉換。試著移除例子中float64uint的轉換看看會發生什麼。

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 int = int(f)
	fmt.Println(x, y, z)
}

型別推導

在宣告一個變數而不指定其型別時(即使用不帶型別的:=語法或var =表示式語法),變數的型別由右值推導得出。

當右值聲明瞭型別時,新變數的型別與其相同:

var i int
j := i // j 也是一個 int

不過當右邊包含未指明型別的數值常量時,新變數的型別就可能是int,float64complex128了,這取決於常量的精度:

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

嘗試修改示例程式碼中v的初始值,並觀察它是如何影響型別的。

package main

import "fmt"

func main() {
	v := 42.00000000000001 // 修改這裡!
	fmt.Printf("v is of type %T\n", v)
}

常量

常量的宣告與變數類似,只不過是使用const關鍵字。

常量可以是字元、字串、布林值或數值。

常量不能用:=語法宣告。

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)
}

數值常量

數值常量是高精度的

一個未指定型別的常量由上下文來決定其型別。

再嘗試一下輸出needInt(Big)吧。

int型別最大可以儲存一個 64 位的整數,有時會更小。)

int可以存放最大64位的整數,根據平臺不同有時會更少。)

package main

import "fmt"

const (
	// 將 1 左移 100 位來建立一個非常大的數字
	// 即這個數的二進位制是 1 後面跟著 100 個 0
	Big = 1 << 100
	// 再往右移 99 位,即 Small = 1 << 1,或者說 Small = 2
	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))
}