文章目錄
- 一、Go環境
- 二、Go依賴
- go deps
- go module(1.13+默認的包管理工具)
- 三、go module
- 四、go語法
- 4.1 變數
- 4.2 常量
- 4.3 資料型別
- 4.3.1 整型
- 4.3.2 數字字面量語法
- 4.3.2 浮點型
- 4.3.3 復數
- 4.3.4 布林值
- 4.3.5 字串 【區別Java】
- 4.3.6 字串轉義符
- 4.3.7 多行字串
- 4.3.8 byte和rune型別
- 4.3.9 修改字串
- 4.4 型別轉換
- 五、流程控制 if for
- 5.1 if
- 5.2 for
- 5.3 for range
- 5.4 switch case
- 5.5 goto
- 5.6 break
- 5.7 continue
- 六、陣列
- 6.1 陣列
- 6.2 多維陣列
- 6.3 初始化
- 6.4 陣列回圈
- 6.5 陣列的本質
- 七、切片
- 7.1 本質
- 7.2 go 的slice 和 陣列比較
- 7.3 slice語法
- 7.3.1 宣告
- 7.3.2 切片運算式
- 7.3.3 make
- 7.3.4 切片判斷
- 7.3.5 slice的賦值拷貝
- 7.3.6 slice 的遍歷
- 7.3.7 API
- 7.3.8 examples
- 八、map
- 8.1 宣告
- 8.2 判斷某個鍵是否存在
一、Go環境
安裝步驟略,
可使用go version 判斷是否安裝成功
較高版本go會自動添加 GOROOT GOPATH(反正1.15可以)
- go build
- go build -o “x.exe”
- go run main.go
- go install 先編譯,然后拷貝到
$GOPATH/bin中
二、Go依賴
問:為啥要有go 依賴的?
答: 早期,go所有依賴的三方庫都在 GOPATH 下,同一個庫的只能保存一個版本的代碼,若不同的專案依賴同一個三方庫的不同版本,怎破?
目前已引入vendor模式,若專案目錄下有vendor目錄,go工具鏈優先使用vendor內的包,godep就是一個實作vendor模式 的三方依賴管理工具,
go deps
go module(1.13+默認的包管理工具)
三、go module
go module 匯入本地包,分兩種情況:
- 1、一個專案下的包
- 同一個專案(project) 可以定義多個包 (package)
- 2、
前面幾節都是工程化的方面的內容,下面是語法方面的,
四、go語法
4.1 變數
var name string
var age = 18
func main() {
n := 10
}
func main() {
x, _ := foo()
_, y := foo()
fmt.Println("x=", x)
fmt.Println("y=", y)
}
- 變數先宣告再使用;同一個作用域不能重復宣告
- 跟java類似,在宣告時會初始化時機默認值
- 整型–>0
- 浮點型–> 0
- 字串變數 --> 空串 【這個與java倒是不一樣】
- 切片、函式、指標變數 --> nil
- 支持型別推導
- 支持函式內 短宣告
- 支持匿名變數
- 匿名變數不占用命名空間,不分配記憶體,也不存在重復宣告(lua中的啞元變數)
- 字符 _ 用于占位,表示忽略值
4.2 常量
const a = 10
const(
c = "ht"
d = 1.0
)
const(
c = "ht"
d
)
const (
e = iota //常量計數器,簡單說就是 const 陳述句塊的行索引,主要用于定義 列舉
f //
g
h
)
const (
n1 = iota //0
n2 //1
_ // 使用 _ 跳過某些值
n4 //3
)
- 常量定義的時候, 必須賦值,且之后不能再去更改了,
- 支持一次宣告多個常量
- 一次宣告多個常量時,若省略了值,則表示和上一行值相同
iota: const 陳述句塊的行索引,列舉中用得比較多
4.3 資料型別
除了基本的整型、浮點型、布爾型、字串之外,還有陣列、切片、函式、結構體、map、通道等,可見,Go中的資料型別十分豐富,
4.3.1 整型
- uinit8 --> 無符號 8位 整型(0 --> 255),其實就是
byte - …
下面介紹特殊整型:
- uint --> 32位系統上是uint 32 (無符號32位整型), 64位系統上是 uint64 (無符號64位整型)
- int --> 32位系統上是 int32 (有符號32位整型),64位系統上是 int64(有符號64位整型)
- uintptr --> 無符號整型,用于存放一個指標
注意:
- 在使用int 和 uint ,不能假定是32 或 64 位,要考慮不同平臺上的差異
len()回傳值根據不同平臺而不同,切片、map 元素數量可以用int表示,在涉及二進制運輸、讀寫檔案時,為保持檔案結構不受平臺影響,不要使用intuint
4.3.2 數字字面量語法
主要是為了方便以二進制、八進制、十六進制浮點數定義數字,
4.3.2 浮點型
- float32
- float64
4.3.3 復數
- complex64
- complex128
4.3.4 布林值
也不過是true false .
go語言中:
- 不能將整型強轉為布林值
- 布爾數不能參與數值運算,不能與其他型別資料轉換
4.3.5 字串 【區別Java】
Go中的字串是原生資料型別,使用字串跟使用int 這些資料型別一樣,Go字串內部使用 UTF-8 編碼,可以直接 s:= "非AscII字符"
4.3.6 字串轉義符
\r 回車
\n 換行
\t 制表符
\' 單引
\'' 雙引
\\ 反斜杠
4.3.7 多行字串
s1 := `第一行
第二行
第三行
`
fmt.Println(s1)
反引號間換行被視為字串的換行,所有的轉義字符都無效,文本原樣輸出
4.3.8 byte和rune型別
Go中的字符有兩種:
- uint8型別,或者叫 byte 型,代表了ASCII碼的一個字符,
- rune型別,代表一個 UTF-8字符,
當需要處理中文、日文或者其他復合字符時,則需要用到rune型別,rune型別實際是一個int32,
UTF-8 編碼下,一個中文字符占3~4 個位元組,我們不能簡單按照位元組去修改包含中文的字串,否則可能亂碼,
GO的字串底層是一個byte陣列,可以和byte[] 相互轉化,字串的長度就是 byte[]的長度,rune型別用來表示 utf-8 字符,一個 rune字符由一個或多個byte 組成,
Go中字串也是不能修改的,我們常說的修改一個字串的操作實際上是復制一個新字串的程序,
注意,在java中, 字串是一個char[],和go還是不一樣的,
4.3.9 修改字串
要修改字串,需要先將其轉換成[]rune或[]byte,完成后再轉換為string,無論哪種轉換,都會重新分配記憶體,并復制位元組陣列,
s2 := "白蘿卜" // 字串
s3 := []rune(s2) // 強轉為 rune 切片
s3[0] = '紅'
fmt.Print(string(s3)) //rune強轉為字串
c1 := "紅" // string
c2 := '紅' // int32
fmt.Printf("c1: %T, c2: %T \n", c1, c2)
c3 := "H" // string
c4 := 'H' // int32
fmt.Printf("c3: %T, c4: %T", c3, c4)
c5:= byte(c4) // uint8 ,其實就是 byte
fmt.Printf("c5 : %T \n", c5) // uint8
fmt.Printf("c5: %d", c5) // 72
4.4 型別轉換
Go語言中只有強制型別轉換,沒有隱式型別轉換,該語法只能在兩個型別之間支持相互轉換的時候使用,
T(運算式) 語法實作了強轉
同時,%T 可以列印出變數的資料型別
fmt.Printf("%T", "字串")
五、流程控制 if for
5.1 if
5.2 for
go 語言中,for 可以當做while一樣來用
func fun2(){
i := 1
for i<=10{
fmt.Println(i)
i++
}
}
OR:
死回圈
for {
回圈體陳述句
}
5.3 for range
for range遍歷陣列、切片、字串、map 及通道(channel)
- 陣列 、切片、字串 回傳索引和值
- map ,回傳key和值
- channel ,回傳 通道內的值
func fn3() {
s := "hello你好" // 這里的 “好” 的索引并不是 6,而是 8 ,這跟java 的string還確實差異很大,go的string 是個位元組陣列,不是字符陣列
for i,v := range s{ //i 索引 ; v 值
fmt.Printf("%d %c \n", i,v)
}
}
5.4 switch case
fallthrough語法可以執行滿足條件的case的下一個case(為了兼容C語言)
func fallthroughDemo() {
s := "a"
switch {
case s == "a":
fmt.Print("1")
fallthrough
case s == "b": // 這一句也會執行
fmt.Print("2")
case s == "c":
fmt.Print("3")
default:
fmt.Print("...")
}
}
5.5 goto
略,goto 盡量不要用
5.6 break
break可以結束 for switch select的代碼塊,
break 還可以 在陳述句后面加標簽,表示退出某個標簽對應的代碼塊,標簽要求必須定義在對應的 for switch select代碼塊上,
5.7 continue
結束本次回圈,開始下一次回圈,
continue陳述句后添加標簽時,表示開始標簽對應的回圈
六、陣列
6.1 陣列
陣列: 同一種資料型別元素的集合,使用時,可以修改陣列成員,但是不能改變陣列大小,定義如:
var a [5]int
- 陣列的長度必須是常量,并且長度是陣列型別的一部分
- 陣列長度定義后,不能再去修改
[5]int [10]int是不同型別的陣列
6.2 多維陣列
go 支持多維陣列
6.3 初始化
陣列有多種初始化方式,
func fn5() {
var a = [3]string{"a","b","c"}
fmt.Println(a)
var b = [...]int{1,2,3}
fmt.Println(b)
c:=[...]int{1:1,4:4}
fmt.Print(c)
}
6.4 陣列回圈
- for 回圈
- for …range …
6.5 陣列的本質
1、陣列是值型別:
賦值和傳參會復制整個陣列,若改變副本的值,不會改變本身的值,
2、陣列支持 “==“、”!=” 運算子,因為記憶體總是被初始化過的,
3、[n]*T表示指標陣列,*[n]T表示陣列指標 ,
七、切片
7.1 本質
slice 本質就是個陣列指標 + 長度 + 容量,
切片本身不存值,存值的是切片指向的底層陣列
切片指向的陣列的記憶體必須是連續的


go的切片類似Java 的ArrayList ,不過使用起來差別還是挺大的,
7.2 go 的slice 和 陣列比較
- Slice 是動態陣列,可變長;陣列長度是陣列的一部分,是定長的
- Slice 是傳址,而陣列是傳值
7.3 slice語法
7.3.1 宣告
var name []T
跟陣列宣告比較起來,只不過是不需要指定的 長度而已,
var a []string // 宣告字串切片
var c = []string {} // 宣告字串切片并初始化,通常宣告即可操作,不需要特地初始化
var d = []bool {true} // // 宣告字串切片并初始化,并給元素賦值
fmt.Println(a == nil) //true 底層陣列未指定,因此為nil
fmt.Println(c == nil) //false
fmt.Println(len(d)) // len() 內置函式(builtin)求長度 (長度=1)
fmt.Println(cap(d)) // cap() 內置函式 求容量capacity (容量=1)
7.3.2 切片運算式
指從 陣列、字串,指向陣列或字串的指標構造字串或切片,有兩種形式:簡單運算式 + 完整運算式,
簡單運算式:
func fn9(){
a := [5]int{1,2,3,4,5} // 這是一個陣列
b := a[1:3] // 這是一個從陣列 構造的 slice, 左閉右開,即取了 a[1] a[2]作為 切片的新元素
fmt.Printf("%T %v \n", b, b)
fmt.Printf("len:%v \n", len(b))
fmt.Printf("cap:%v \n", cap(b)) // 容量 = 原陣列容量5 - 起始切片索引(1) = 4
fmt.Println("---------")
c:= b[3:4] //切片再切片 , 右邊索引的最大值= cap(b),也就是 4
fmt.Printf("%v \n", c)
fmt.Printf("len:%v \n", len(c))
fmt.Printf("cap:%v \n", cap(c))
}
7.3.3 make
上一節,是基于 陣列來構造一個切片,假如我們要動態創建一個切片,
則 `make([]T, size, cap)
func fn10() {
a:= make([]int, 10) // make 關鍵字 --> 創建 切片
fmt.Printf("%T \n", a) //[]int --> illustrates that it's a slice
fmt.Printf("len:%v \n", len(a)) // len:10 --> 注意,len并不是0
fmt.Printf("cap:%v \n", cap(a)) //cap :10
fmt.Printf("%v \n", a) //[0 0 0 0 0 0 0 0 0 0] --> 每個元素都有默認值
}
當然,也可以:
a:= make([]int, 2,10) 這樣指定 len 和 cap
7.3.4 切片判斷
1、判斷切片是否為空不能使用s == nil,而應該使用len == 0 (任何情況下都是如此,即使是宣告但是沒有初始化的)
2、切片之間不能比較,不能使用== 直接判斷兩個切片是否具有完全一樣的元素,切片只能和 nil 比較,
一個 nil值的切片,沒有底層陣列,切片長度、容量都為0,但是反過來則不一定:我們不能說,一個長度、容量=0 的切片一定是nil,
var s1 []int // s1: len (0), cap (0), (==nil?) true --> 只宣告,未初始化
s2 := []int{} // s2: len (0), cap (0), (==nil?) false --> 宣告并初始化了
s3 := make([]int,0) // s3: len (0), cap (0), (==nil?) false --> 宣告并初始化了
7.3.5 slice的賦值拷貝
拷貝前后,兩個slice實際上共享了同一個底層陣列,因此對一個slice的增刪改會影響到另一個slice,【傳址】
7.3.6 slice 的遍歷
slice的遍歷:
- for
- for range
7.3.7 API
- append
- append操作可能引起擴容,擴容策略會因為元素型別的不同而不同
- copy --> 復制切片
- 切片中洗掉元素
- slice并沒有直接洗掉元素的API
- 要從切片a中洗掉索引為index的元素,操作方法是
a = append(a[:index], a[index+1:]...)【Java表示:這種用法實在是繁瑣啊,,】
7.3.8 examples
1、case1 :append
var b = make([]string, 5, 10)
fmt.Println("before append:", b) // [ ] --> 這里是 空串組成的 切片
for i := 0; i < 10; i++ {
b = append(b, fmt.Sprintf("%v", i))
}
fmt.Println("after append", b) // [ 0 1 2 3 4 5 6 7 8 9] --> 這里 前面幾個元素還是空串
fmt.Println("after append,the len is:", len(b)) //15
fmt.Println("after append,the cap is:", cap(b)) //20
假如:第一句代碼指定len = 0,也就是說:
var b = make([]string, 5, 10)
則前5個元素就不是空串了
2、case2 :排序
內置的sort包對陣列var a = [...]int{3, 7, 8, 9, 1}進行排序
func fn13() {
var a = []int{1, 5, 4, 9, 8, 0}
sort.Sort(sort.IntSlice(a))
fmt.Println(a)
}
3、case3: 洗掉
func fn14(){
a := [3]int{1,3,5} // a is an array
fmt.Println(a, len(a), cap(a))
b := a[:] //b is a slice
fmt.Println(b, len(b), cap(b))
b = append(b[:1], b[2:]...) // 實際效果是洗掉了 元素 “3”,本質上會修改底層陣列
fmt.Println(b, len(b), cap(b)) // [1 5] 2 3
fmt.Println(a) // [1 5 5] --> 這里會修改 底層陣列第二個值為 5
// 假如我們從切片修改一個值
b[0] =100
fmt.Println(a) //[100 5 5] --> 依然改動了底層陣列的值
}
八、map
8.1 宣告
map是 參考型別,必須先初始化才能使用,
宣告語法: map[KeyType]ValueType
map型別的變數默認初始值為<nil>,需要先make
func fn22() {
// 方法1
var dict =make(map[string]int, 10)
dict["a"] =1
dict["b"] =2
fmt.Println(dict)
fmt.Printf("%T \n", dict) // map[string]int
// 方式2
var dict2 = map[string]int{
"c":3,
"d":4,
}
fmt.Println(dict2)
}
8.2 判斷某個鍵是否存在
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/246599.html
標籤:區塊鏈
上一篇:Linux下的WPS安裝
