Go語言--基礎語法筆記
###
換了工作,好久沒有新增新文章了,本來是想更新到github上的,想想還是在部落格裡放著,感覺以前的文章都沒有很仔細,都只是問題處理的記錄,
以後想新加一些整理的筆記也好
###
主要內容
2.1變數
2.2資料型別
2.3資料型別相互轉換
2.4指標
2.5變數生命期
2.6字串應用
2.7常量 2.8類型別名
2.1變數
2.1.1 宣告變數
功能:儲存使用者的資料
注意: 變數必須經過宣告才能開始使用
變數宣告格式:
-
標準格式
var 變數名 變數型別
以關鍵字var開頭,後置變數型別,行尾無線分號
package main import ("fmt") func main() { var a int var b string var c []float32 var d func() bool var e struct{ x int } }
-
批量格式
使用var關鍵字 和括號
package main import ("fmt") func main() { var ( a int b string c []float32 d func() bool e struct{ x int } ) }
2.1.2 初始化變數
-
整型和浮點型變數預設值:0
-
字串變數的預設值空字串
-
布林型預設值為bool
-
切片、函式、指標變數的預設值為nil
1.標準格式
var 變數名 變數型別 = 表示式
var hp int = 100
2.編譯器推導的型別
var hp1 = 100
標準格式基礎上,省略int,編譯器推導
var attack = 40 var defence = 20 var damageRate float32 = 0.17 var damage = float32(attack-defence) * damageRate fmt.Println(damage) // 3.4
3.短變數宣告並初始化
hp := 100
注意:變數已經被宣告過了,再次宣告並賦值,使用短變數宣告會編譯報錯
var p string p := '123' fmt.Println(p) // 錯誤資訊:no new variables on left side of :=(44.4) // var p 聲明瞭p變數, p := '123' 會再次宣告並賦值 hp3 := 50 fmt.Println(hp3)
2.1.3 多個變數同時賦值
順序:從左到右
var a int = 100 var b int = 200 a, b = b, a fmt.Println(a, b) //200 100
2.1.4 匿名變數
匿名變數用一個"_"下滑線表示
只需要在變數宣告的地方,用下劃線代替即可
package main import ("fmt") func main() { a1, _ := getData() _, b1 := getData() fmt.Println(a1, b1) } type IntSlice []int // 編寫一個len方法,提供切片的長度 func (p IntSlice) Len() int { return len(p)} // 根據提供i,j元素索引,兩個元素進行比較,返回比較結果 func (p IntSlice) Less(i, j int) bool { return p[i] < p[j]} // 根據提供i,j元素索引,交換兩個元素的值 func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i]} func getData() (int, int) { return 200, 100 }
2.2 資料型別
2.2.1 整型
兩種: 長度 int8 int16 int32 int64 無符號 uint8 uint16 uint32 uint64
2.2.2 浮點型
兩種:float32和float64
fmt.Println("hello world") fmt.Printf("%f\n", math.Pi) fmt.Printf("%.2f\n", math.Pi)
2.2.3 布林型
注意:go不允許將整型型別轉換為布林型, 無法參與數值運算,也無法跟其他型別進行轉換
var n bool fmt.Println( int(n) * 2 ) //cannot convert n (type bool) to type int
2.2.4 字串
用雙引號括起來的內容就是為字串的內容
str := "hello world string" ch := "中文" fmt.Println(str, ch) //hello world string 中文
-
字串轉義符
符合 說明 \r 回車 \n 換行符 \t 製表符 ' 單引號 " 雙引號 \ 雙斜槓 fmt.Println( "str := \"c:\\Go\\bin\\go.exe\" ") str := "c:\Go\bin\go.exe"
-
字串實現基於utf-8編碼
-
定義多行字串
const longstr = ` 第一行 第二行 \r\n 。。。 ` fmt.Println(longstr) //第一行 //第二行 //\r\n //。。。 const codeTemplate = ` // Generated by github.com/davyxu/cellnet/protoc-gen-msg // DO NOT EDIT!{{range.Protos}} // Source:{{.Name}} {{end}} package {{.PackageName}} {{if gt .TotalMessages 0}} import ( "github.com/davyu/cellnet" "reflect" _ "github.com/davyxu/cellnet/codec/pb" ) {{end}} func init() { {{range .Protos}} //{{.Name}}{{range .Messages}} cellnet.RegisterMessageMeta("pb", "{{.FullName}}") reflect.TypeOf((*{{.Name}})(nil)).Elem(), {{.MsgID}}) {{end}} {{end}} } ` fmt.Println(codeTemplate)
2.2.5 字元
字串中每一個元素都叫字元 兩種: 一種為uint8型別
或是 byte型別
代表ascll碼的一個字元 另一種為rune型別
, 代表一個UTF-8型別
,實際為int32
用於處理中文、日文等複合字符 使用fmt.Printf 中“%T”
輸出變數實際型別,可用於檢視byte和rune型別
var a byte = 'a' fmt.Printf("%d %T\n", a, a) var b rune = '中' fmt.Printf("%d %T\n", b, b) //97 uint8 //20013 int32
2.2.7 切片 -- 能動態分配的空間
一個擁有相同型別元素的可變長的序列
var name []T
T 代表切片元素型別, 即可以整型、浮點型、布林型、切片、map、函式等
t := make([]int, 5) t[0] = 1 t[1] = 2 t[3] = 3 fmt.Println(t) //[1 2 0 3 0] str1 := "hello world" fmt.Println(str1[6:]) //world
2.3 轉換不同的資料型別
格式:
T(表示式)
輸出各數值範圍
package main import ( "fmt" "math" ) func main() { fmt.Println("int8 range:", math.MinInt8, math.MaxInt8) fmt.Println("int16 range:", math.MinInt16, math.MaxInt16) fmt.Println("int32 range:", math.MinInt32, math.MaxInt32) fmt.Println("int64 range:", math.MinInt64, math.MaxInt64) int8 range: -128 127 int16 range: -32768 32767 int32 range: -2147483648 2147483647 int64 range: -9223372036854775808 9223372036854775807 //初始化一個32位整型值 var a1 int32 = 1047483647 fmt.Printf("int32: 0x%x %d\n", a1, a1) //nt32: 0x3e6f54ff 1047483647 //int32 轉為 int16, 發生數值截斷 b1 := int16(a1) fmt.Printf("a1 int16: 0x%x %d\n", b1, b1) //a1 int16: 0x54ff 21759 //將常量儲存為float32型別 var c float32 = math.Pi //轉為int型別,浮點數發生精度丟失 fmt.Println(int(c)) //3 }
2.4 指標
兩個核心: 一種是型別指標
,允許對這個指標型別的資料進行修改。 傳遞資料使用使用指標,而無須拷貝資料 型別指標不能進行偏移和運算 二種是切片
, 由指向起始元素的原始指標、元素數量和容量組成
2.4.1 認識指標地址和指標型別
每個變數在執行時都會被記憶體分配一個地址,這個地址代表變數在記憶體中的位置 使用“&”操作符放在變數前面對變數進行“取地址”操作 格式:
ptr := &variable //variable的型別為T
其中v代表被取地址的變數,被取地址的variable使用ptr變數進行接收,ptr的型別為“T”,稱作T的指標型別。“”代表指標
package main import ( "fmt" "math" ) func main() { var cat int = 1 var str2 string = "banana" fmt.Printf("%p, %p\n", &cat, &str2) } //0xc00004e0e8, 0xc0000421f0 為cat,str2取地址後的指標值
注意:變數、指標和地址三種的關係是:每個變數都擁有地址,指標的值就是地址
2.4.2 從指標獲取指標指向的值
對變數“&”取地址操作後獲得這個變數的指標,對指標使用“*”操作,就是指標取值
package main import ( "fmt" "math" ) func main() { var house = "Malibu Point 10880, 90265" // 對字串取地址,ptr1型別為*string ptr1 := &house // 列印ptr型別 fmt.Printf("ptr1 型別:%T\n", ptr1) // 列印ptr指標地址 fmt.Printf("ptr1 地址:%p\n", ptr1) // 對指標進行取值操作 value := *ptr1 // 取值後型別 fmt.Printf("value 型別:%T\n", value) // value值 fmt.Printf("value:%s\n", value) } // ptr1 型別:*string // ptr1 地址:0xc000042200 // value 型別:string // value:Malibu Point 10880, 90265
總結:
取地址“&”和取值“”是一對互補操作符,“&”取地址,"&"根據地址取出地址指向的值 1.對變數進行其地址(&)操作,可獲得這個變數的指標變數 2.指標變數的值是指標地址 3.對指標變數進行取值()操作,可以獲得指標變數指向的原變數的值
2.4.3 使用指標修改值
x, y := 1,2
package main import ( "fmt" "math" ) func main() { //錯誤示例 swap1(&x, &y) fmt.Println("x: ",x, "y:", y) //x: 1 y: 2 //正確 swap(&x, &y) fmt.Println("x: ", x, "y: ",y) //x: 2 y: 1 } // 交換函式 func swap(a, b *int) { // 取a的指標的值,賦給臨時變數t t := *a //取b指標的值,賦值給a指標指向的變數 *a = *b //a指標的值賦值給b指標指向的變數 *b = t } // 錯誤示例 func swap1(a, b *int) { b, a = a, b }
2.4.5 建立指標的另一種方法--new()函式
new(型別)
str3 := new(string) *str3 = "ninja" fmt.Println(*str3) fmt.Println(str3) //ninja //0xc000042230
2.6 字串應用
2.6.1 計算機字串長度 -- len()
go 語言字串都是以UTF-8格式儲存,每個中文佔用3個字元
tip1 := "genji is a ninja" fmt.Println(len(tip1)) // 16 tip2 := "忍者無敵" fmt.Println(len(tip2)) //12 // 使用RuneCountInString()統計Uncode字元數量 fmt.Println(utf8.RuneCountInString("忍者"))
總結
-
ASCII字串長度使用len()函式
-
Unicode字串長度使用utf8.RuneCountInString()函式
2.6.2 遍歷字串 -- 獲取每個字串
兩種寫法
-
遍歷每一ASCII字元, 使用for迴圈遍歷
theme := "阻擊 start" for i := 0; i < len(theme); i++ { fmt.Printf("ascii: %c %d\n", theme[i], theme[i]) } // ascii: é 233 // ascii: • 152 // ascii: » 187 // ascii: å 229 // ascii: • 135 // ascii: » 187 // ascii: 32 // ascii: s 115 // ascii: t 116 // ascii: a 97 // ascii: r 114
-
按Unicode字元遍歷字串
for _, s := range theme { fmt.Printf("Unicode %c %d\n", s, s) } // Unicode 阻 38459 // Unicode 擊 20987 // Unicode 32 // Unicode s 115 // Unicode t 116 // Unicode a 97 // Unicode r 114 // Unicode t 116
總結:
-
ASCII字串遍歷直接使用下標
-
Unicode字串遍歷使用for range
2.6.3 獲取字串的某一段字元
string.Index() 在字串中搜索另一個子串
tracer := "努力擁抱每一天,不斷成長" comma := strings.Index(tracer, "每一天") posi := strings.Index(tracer[comma:], "成長") fmt.Println(comma, posi, tracer[comma+posi:]) // 12 18 成長
總結:
-
strings.Index:正向搜尋子字串
-
string.LastIndex: 反向搜尋自字串
搜尋的起始位置可以通過切片偏移製作
2.6.4 修改字串
go語言無法直接修改每一個字元元素,只能通過重新構造新的字串並賦值給原來的字串變數
angel := "Hero nerver die" arrayBytes := []byte(angel) for i := 5; i <= 10; i++ { arrayBytes[i] = '-' } fmt.Println(arrayBytes) // [72 101 114 111 32 45 45 45 45 45 45 32 100 105 101] fmt.Println(string(arrayBytes)) // Hero ------ die
總結
-
Go語言的字串是不可以改變的
-
修改字串時,可以將字串轉換為[]byte進行修改
-
[]byte 和string 可以通過強制型別轉換互換
2.6.5 連線字串
可以使用加號“+”連線 可以使用類似於StringBuilder的機制連線,更高效
hamer := "GO GO GO" sickle := "You Can" // 宣告位元組緩衝 var stringBuilder bytes.Buffer // 將字串寫入緩衝區 stringBuilder.WriteString(hamer) stringBuilder.WriteString(sickle) //將緩衝以字串形式輸出 fmt.Println(stringBuilder.String()) // GO GO GOYou Can
-
bytes.Buffer可以緩衝並寫入各種位元組陣列,字串也是一種字串陣列,使用writeString()
-
將需要連線的字串,通過bytes.Buffer宣告緩衝stringBuilder呼叫WriteString()方法寫入裡面,
-
再通過stringBuilder.String()方法將緩衝轉換為字串
2.6.6 格式化
寫法: fmt.Sprintf(格式化樣式,引數列表) 格式化樣式:字串形式,格式化動詞以%開頭 引數列表:多個引數以逗號分隔,個數必須與格式化中樣式個數一一對應
var progress = 2 var target = 8 // 兩引數格式化 title := fmt.Sprintf("以完成%d個任務,還差%d個就完成", progress, target) fmt.Println(title) // 以完成2個任務,還差8個就完成 pi := math.Pi // 按數值本身格式輸出 variant := fmt.Sprintf("%v %v %v", "月球基地", pi, true) fmt.Println(variant) // 月球基地 3.141592653589793 true profile := &struct { Name string HP int }{ Name: "stat", HP: 150, } fmt.Printf("使用'%%+v' %+v\n", profile) fmt.Printf("使用'%%#v' %#v\n", profile) fmt.Printf("使用'%%T' %T\n", profile) // 使用'%+v' &{Name:stat HP:150} // 使用'%#v' &struct { Name string; HP int }{Name:"stat", HP:150} // 使用'%T' *struct { Name string; HP int }
base64編碼解碼示例
package main import ( "fmt" "encoding/base64" ) func main() { // 需要處理的字串 message := "Away from keyboard. https://golang.org/" // 編碼訊息, 傳入的字串需轉為位元組陣列,才能供這個函式使用 encodeMessage := base64.StdEncoding.EncodeToString([]byte(message)) // 輸出編碼完成的訊息 fmt.Println(encodeMessage) // 解碼訊息 data, err := base64.StdEncoding.DecodeString(encodeMessage) // 出錯處理 if err != nil { fmt.Println(err) } else { fmt.Println(string(data)) } // QXdheSBmcm9tIGtleWJvYXJkLiBodHRwczovL2dvbGFuZy5vcmcv // Away from keyboard. https://golang.org/ }