1. 程式人生 > >Go語言學習之懶人速成

Go語言學習之懶人速成

在上一篇《入門篇》,已經提高了Go的安裝和使用,接下來我們一起學習一下Golang的基礎語法 

為響應一起交流的朋友們的吐槽,後續文章將陸續加上目錄結構,方便大家閱讀(主要還是懶,O(∩_∩)O) orz......

- api文件
- 包 - package
- main方法
- 變數
- 常量
- iota關鍵字
- 陣列
- fmt是什麼鬼

------------------------------------------------------------------------------------

當然,可能有的朋友沒有VPN,連線不上官網,有一個本地檢視文件的方式,如下:

$> go help doc
usage: go doc [-u] [-c] [package|[package.]symbol[.method]]
Doc prints the documentation comments associated with the item identified by its
arguments (a package, const, func, type, var, or method) followed by a one-line
summary of each of the first-level items "under" that item (package-level
declarations for a package, methods for a type, etc.).
Flags:
	-c
		Respect case when matching symbols.
	-cmd
		Treat a command (package main) like a regular package.
		Otherwise package main's exported symbols are hidden
		when showing the package's top-level documentation.
	-u
		Show documentation for unexported as well as exported
		symbols and methods.

或者使用http,瀏覽器方式檢視

$> godoc -http=:8080

接下來,你就可以使用 http://localhost:8080 或 http://127.0.0.1:8080 在本地使用瀏覽器進行瀏覽api文件了。

1、什麼是包(package)?

我們在使用其它語言的情況,比如Java(本主是Java開發出身,0rz,以此為例),是有“包”這個概念的,其實,就可以簡單的理解為是便於管理和組織所有的檔案所使用的,比如java中常用的類String,它就隸屬於“java.lang”包下的類。(當然,新手不理解也沒有關係)。在Go當中,也是類似的概念,它將我們的go檔案(檔案的字尾名為“.go”)組織起來,可以方便進行歸類、複用等。 


你會看到這樣的一些檔案結構,比如encoding包,下面就有base32、base64、hex、json等等,當需要使用時,則

//使用“import”關鍵字進行匯入,比如:

import "fmt"

在開篇《入門篇》中,所講到的編寫“hello world”使用了“fmt”,就使用這樣的匯入方式,當需要匯入多個包時,可以使用

import (
  "fmt"
  "os"
)

包的命名

go語言的包的命名,遵循簡潔、小寫、和go檔案所在目錄同名的原則,這樣就便於我們引用,書寫以及快速定位查詢。對於在企業當中開發的程式而言,我們一般採用域名作為頂級包名的方式,這樣就不用擔心和其他開發者包名重複的問題了,比如公司的域名是`www.bboyHan.com`,那麼開發的go程式都以`bboyHan.com`作為全路徑中的最頂層部分,匯入開發的工具包則可以寫為:

package main

import "bboyHan.com/utils"

------------------------------------------------------------

2、Main

我們知道,在java當中,有一個主程式的入口main()方法,而Go語言程式,也是類似。當把一個go檔案的包名宣告為main時,就等於告訴go編譯程式,這是一個可執行程式,那麼go編譯程式就會嘗試把它編譯為一個二進位制的可執行檔案。如果沒有這個函式,程式就無法執行。

//注意點:在go語言裡,同時要滿足main包和包含main()函式,才會被編譯成一個可執行檔案。

package main

import "fmt"

func main(){
  fmt.Println("接下來,請在這裡搞事情。")
}

那麼,思考一個問題:Go編譯器又是如何去尋找各個檔案、包之間的依賴關係而構建程式的呢

上一文當中,我們提到了環境變數GOROOT和GOPATH兩個概念,這是兩個定義路徑的環境變數,GOROOT是安裝Go的路徑,比如 C:\go ;GOPATH是我們自己定義的開發者個人的工作空間,比如C:\workspace\src\bbboyHan。

編譯器會使用我們設定的這兩個路徑,再加上import匯入的相對全路徑來查詢磁碟上的包,比如我們匯入的fmt包,編譯器最終找到的是 C:\go\fmt 這個位置。對於包的查詢,是有優先順序的,編譯器會優先在GOROOT裡搜尋,其次是GOPATH,一旦找到,就會馬上停止搜尋。如果最終都沒找到,就會報編譯異常了。

------------------------------------------------------------

3、變數

Go中使用全新的關鍵字var來宣告變數。var我們並不陌生,在Javascript 和C#中均有出現。不同的是Go和C#中變數屬於強型別,在宣告變數後就不允許改變其資料型別。記住,Go屬於強資料型別

宣告及初始化

var a int //宣告一個int型別的變數

var b struct { //宣告一個結構體

  i string

}

var a = 1 //宣告變數的同時賦值,編譯器自動推導其資料型別

a := 1 //這種方式,含義同上,不書寫型別,編譯時會根據value自動推導型別進行匹配

var a int = 2 //宣告變數的同時賦值

var { //批量宣告變數,簡潔
  a int
  b string
}

值得注意的一點,賦值時如果要確定你想要的型別,在Go中是不支援隱式轉換的。如果是定義個float64型別的變數,請寫為

//前提:需要定義一個float型別的變數時:
//正確寫法 
v1 := 3.0 
//錯誤寫法
v1 := 3 
------------------------------------------------------------

4、常量

使用constant關鍵字進行定義,官方文件內容

const a = 2 + 3.0          // a == 5.0   (untyped floating-point constant)
const b = 15 / 4           // b == 3     (untyped integer constant)
const c = 15 / 4.0         // c == 3.75  (untyped floating-point constant)
const Θ float64 = 3/2      // Θ == 1.0   (type float64, 3/2 is integer division)
const Π float64 = 3/2.     // Π == 1.5   (type float64, 3/2. is float division)
const d = 1 << 3.0         // d == 8     (untyped integer constant)
const e = 1.0 << 3         // e == 8     (untyped integer constant)
const f = int32(1) << 33   // illegal    (constant 8589934592 overflows int32)
const g = float64(2) >> 1  // illegal    (float64(2) is a typed floating-point constant)
const h = "foo" > "bar"    // h == true  (untyped boolean constant)
const j = true             // j == true  (untyped boolean constant)
const k = 'w' + 1          // k == 'x'   (untyped rune constant)
const l = "hi"             // l == "hi"  (untyped string constant)
const m = string(k)        // m == "x"   (type string)
const Σ = 1 - 0.707i       //            (untyped complex constant)
const Δ = Σ + 2.0e-4       //            (untyped complex constant)
const Φ = iota*1i - 1/1i   //            (untyped complex constant)

------------------------------------------------------------

有趣的一點,就是Go在一些情況下,會做一些調整,比如:

func  main(){
  a :=8
  a =8.5       // 將編譯錯誤:constant 8.5 truncated to integer
  fmt.Println(a)
}
func  main(){
  a := 3
  a = 3.0       // 編譯可通過,執行無錯誤
  fmt.Println(a)
}

也就是說,Go在不損失精度的情況下會把3.0這類浮點數視作整數3,如果型別顯式指定了,在表示式當中就不會產生變化。在使用的時候會根據上下文需要的型別轉化為實際型別,比如uint8(0) + 1.0就是uint8(1),但是uint8(0)+2.2就會由於2.2無法轉化為uint8而報錯。

當多個常量需要定義時,也可以使用簡易寫法:

//相同型別的情況:
const c_name1, c_name2 = value1, value2
//可以用作列舉
const (
    Unknown = 0
    Female = 1
    Male = 2
)
-----------------------------------------------------------

5、iota

iota,特殊常量,可以認為是一個可以被編譯器修改的常量。在每一個const關鍵字出現時,被重置為0,然後再下一個const出現之前,每出現一次iota,其所代表的數字會自動增加1。

const (
    a = iota  //a = 0
    b = iota  //b = 1
    c = iota  //c = 2
)
//可簡寫為:
const (
    a = iota
    b
    c
)
//進階用法:
const (
    i = 1<<iota  //i = 1
    j = 3<<iota  //j = 6
    k            //k = 12
    l            //l = 24
)
-----------------------------------------------------------

6、陣列

var array [5]int             //宣告
array =  [5]int{1,2,3,4,5}   //初始化
array := [5]int{1,2,3,4,5}   //宣告並初始化
array := [...]int{1,2,3,4,5} //不指定長度進行宣告及初始化
array := [5]int{1:1,3:4}     //只對索引為1和3的值初始化,其餘使用預設初始化值0

因為陣列的建立在記憶體當中是一段連續的空間,所以通過索引進行直接訪問,訪問的效率非常高

func main() {
	array := [5]int{1: 1, 3: 4}
	for i := 0; i < 5; i++ {
		fmt.Printf("索引:%d,值:%d\n", i, array[i])
	}
}

-----------------------------------------------------------

看了上面的程式碼,想必會有朋友會問“fmt”還沒有講呢,下面講解一下fmt包的相關知識

7、“fmt”

fmt包實現了格式化的I/O函式,這點類似C語言中的printf和scanf,但是更加簡單,其中的格式“佔位符”衍生自 C

//常用的格式化輸出
fmt.Printf("start at number %v, end count %v\n",start, count)

佔位符

一般佔位符

符號說明
%v相應值的預設格式
%+v在列印結構體時,預設格式,會新增欄位名
%#v相應值的 Go 語法表示
%T相應值的型別的 Go 語法表示
%%字面上的百分號,並非值的佔位符

布林佔位符
符號說明
%t單詞 true 或 false

整數佔位符

符號說明
%b二進位制表示
%c相應 Unicode 碼點所表示的字元
%d十進位制表示
%o八進位制表示
%q單引號圍繞的字元字面值,由 Go 語法安全地轉義
%x十六進位制表示,字母形式為小寫 a-f
%X十六進位制表示,字母形式為大寫 A-F
%UUnicode 格式:U+1234,等同於 "U+%04X"

浮點數及其複合構成佔位符

符號說明
%b無小數部分的,指數為二的冪的科學計數法,與 strconv.FormatFloat 的 'b' 轉換格式一致。例如 -123456p-78
%e科學計數法,例如 -1234.456e+78
%E科學計數法,例如 -1234.456E+78
%f有小數點而無指數,例如 123.456
%g根據情況選擇 %e 或 %f 以產生更緊湊的(無末尾的 0)輸出
%G根據情況選擇 %E 或 %f 以產生更緊湊的(無末尾的 0)輸出

字串與位元組切片佔位符

符號說明
%s字串或切片的無解譯位元組
%q雙引號圍繞的字串,由 Go 語法安全地轉義
%x十六進位制,小寫字母,每位元組兩個字元
%X十六進位制,大寫字母,每位元組兩個字元

指標
符號說明
%p十六進位制表示,字首 0x
fmt中的方法:
// Print 將引數列表 a 中的各個引數轉換為字串並寫入到標準輸出中。
// 非字串引數之間會新增空格,返回寫入的位元組數。
func Print(a ...interface{}) (n int, err error)

// Println 功能類似 Print,只不過最後會新增一個換行符。
// 所有引數之間會新增空格,返回寫入的位元組數。
func Println(a ...interface{}) (n int, err error)

// Printf 將引數列表 a 填寫到格式字串 format 的佔位符中。
// 填寫後的結果寫入到標準輸出中,返回寫入的位元組數。
func Printf(format string, a ...interface{}) (n int, err error)

// 功能同上面三個函式,只不過將轉換結果寫入到 w 中。
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

// 功能同上面三個函式,只不過將轉換結果以字串形式返回。
func Sprint(a ...interface{}) string
func Sprintln(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string

// 功能同 Sprintf,只不過結果字串被包裝成了 error 型別。
func Errorf(format string, a ...interface{}) error
其它關於fmt的內容未進行詳細解釋的,可以參考官方文件進行進一步研究學習

有任何建議或問題,歡迎加微信一起學習交流,歡迎從事IT,熱愛IT,喜歡深挖原始碼的行業大牛加入,一起探討。

個人微訊號:bboyHan