兵長:喲,最近在幹啥呢
胖sir:在看我之前的go基礎學習資料呢,回顧一下
兵長:那給我分享一下唄,我也想回顧回顧
胖sir:用你的小手指點開你的手機,我來傳給你
兵長:你信不信我的小手指可以帶你飛整個峽谷 . . .
go語言的基本事項
- go run hello.go 直接執行,輸出結果(原理也是編譯後執行)
- go build hello.go 生成可執行程式,執行可執行程式,輸出結果
- 注意 go語言中花括號不能單獨佔一行,否則會報錯
package main
import "fmt"
func main(){ //go語言中此處的花括號不能單獨佔一行,否則會報錯
fmt.Println("hello world")
}
go語言一條語句佔一行,如果一行需要執行多個語句 使用 分號 隔開
go語言的輸出語句有3種方式
- import “fmt” 後適用fmt.Println(x) – 輸出
- println(x) – 輸出
- fmt.Printf(“%d”,x) – 格式化輸出
關鍵字
下面列舉了 Go 程式碼中會使用到的 25 個關鍵字或保留字:
break | default | func | interface | select |
---|---|---|---|---|
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
除了以上介紹的這些關鍵字,Go 語言還有 36 個預定義識別符號:
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
---|---|---|---|---|---|---|---|---|
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
字串的拼接和變數的定義方式
定義變數的三種方式
- 正常使用var定義變數
- 使用var定義變數,但是不定義型別,通過賦初值的方式,go編譯器自動識別
- 使用:=的方式來進行 新變數的定義,僅限於新變數 – 適用於定義在函式內部
//字串 可以使用+ 進行拼接
fmt.Println("this is my func")
fmt.Println("hello ,wolrd" + "xiaozhuzhu")
//定義變數
var name string="xiaomotong"
var age,tail int=24,170
fmt.Println(name, age , tail)
fmt.Println(name)
fmt.Println(age)
fmt.Println(tail)
//定義變數的三種方式
//1
var a int = 1
fmt.Println(a)
//2 使用var定義變數,但是不定義型別,通過賦初值的方式,go編譯器自動識別
var b = "hello"
fmt.Println(b)
//3 使用:=的方式來進行 新變數的定義,僅限於新變數
//:= 左側如果沒有宣告新的變數,就產生編譯錯誤
c := 20
fmt.Println(c)
//c:=30 //報錯,因為c已經不是新變數的
c=30 //正確,是一個正常的賦值操作
fmt.Println(c)
c,d:=40,90 //這樣是合法的
fmt.Println(c,d)
因式分解的方式,僅僅適用於定義全域性變數
//因式分解的方式,僅僅適用於定義全域性變數
var
(
g_a int = 1
g_b,g_c int=1,2
)
空白符
空白識別符號 _ 也被用於拋棄值,如值 5 在:_, b = 5, 7 中被拋棄。
_ 實際上是一個只寫變數,你不能得到它的值。這樣做是因為 Go 語言中你必須使用所有被宣告的變數,但有時你並不需要使用從一個函式得到的所有返回值。
//空白符
_,e := 2,3
fmt.Println(e)
const常量
- 定義const常量
//定義const常量
const width,height = 10,5
var area int=width*height
fmt.Println("面積為", area) //50
- const常量用作列舉
const(
unknow = 0
man = 1
woman = 2
)
println(unknow,man,woman) //0 1 2
- 常量可以用len(), cap(), unsafe.Sizeof()函式計算表示式的值。常量表示式中,函式必須是內建函式,否則編譯不過:
const(
a = "hello"
b = len(a)
c = unsafe.Sizeof(a)
)
println(a,b,c) //hello 5 16
iota的用法
iota,特殊常量,可以認為是一個可以被編譯器修改的常量。
iota 在 const關鍵字出現時將被重置為 0(const 內部的第一行之前),const 中每新增一行常量宣告將使 iota 計數一次(iota 可理解為 const 語句塊中的行索引)。
iota 可以被用作列舉值:
//itoa的用法
const(
g_a = iota
g_b
g_c
g_d
)
const(
g_e = iota
g_f = "hello"
g_g
g_h = iota
g_i
)
const(
g_j = 1<<iota
g_k
g_l
g_m
)
println(g_a,g_b,g_c,g_d)
println(g_e,g_f,g_g,g_h,g_i)
println(g_j,g_k,g_l,g_m)
//0 1 2 3
//0 hello hello 3 4
//1 2 4 8
運算子
go語言的運算子和C語言的運算子基本一致
Go 沒有三目運算子,不能適用?:
算術運算子
關係運算子
邏輯運算子
位運算子
賦值運算子
其他運算子
語言條件語句
- if xxx
if xxx {
...
}
- if xxx {…} else{…}
if xxx{
...
}else{
...
}
- if xxx{ … if xxx { …}}
if xxx{
if xxx {
...
}
...
}
- switch
package main
import "fmt"
func main(){
grade:= 90
if grade >= 90{
println("優秀")
}else if grade >=70 && grade <90{
println("良好")
}else{
println("差")
}
var x interface{} //計算型別
switch i := x.(type){
case nil:
fmt.Printf(" x 的型別 :%T\n",i)
case int:
fmt.Printf("x 是 int 型")
default:
println("未知")
}
}
select
類似於C語言中的select,用於多路IO複用
for迴圈的方式
- 三種方式
- 類似C語言中的for
- 類似C語言中的while
- 死迴圈
package main
import "fmt"
func main(){
//類似C語言中的for
var sum int
for i:=1;i<=10;i++{
sum +=i
}
fmt.Println(sum)
//類似於while
for sum >30{
sum -= 10
fmt.Println(sum)
}
//死迴圈
for {
...
}
- For-each range 迴圈
//for-each range 迴圈的方式
name := []string{"qqq","yyy"}
for i,str:= range name{
fmt.Printf("%d -- %s\n",i,str)
}
//0 -- qqq
//1 -- yyy
------------------------------------------------------------------------
str := []string{"北京", "天津", "山東"}
//可以預設丟掉第二個返回值
for i := range str {
fmt.Printf("%d -- %s\n", i, str[i])
}
函式
go語言的函式,可以有多個返回值,其餘和C語言沒有什麼區別
作用域
與C語言一致
- 區域性變數
- 全域性變數
- 函式形參
陣列&切片
思想和C語言一致,陣列是固定長度的
切片是動態擴容的,類似於C++的vector
切片寫法如下:
name := []string{"xiaomotong","pangsir"}
nums :=[]int{1,2,3,4,5,6}
指標
var ptr1 *int
二級指標
var a int
var ptr *int
var pptr **int
ptr = &a
pptr = &ptr
指標陣列
var ptr [5]*int
結構體
go語言中的結構體變數,和結構體指標,訪問結構體成員的時候,都是使用 點(.)來進行訪問,如下:
//定義一個結構體
type info struct{
name string
age int
height int
}
//使用
var stu info
stu.name = "xiaomotong"
stu.age = 24
stu.height = 170
fmt.Println(stu.name,stu.age,stu.height)
var stu2 *info = &stu
stu2.name = "pangsir"
stu2.age = 24
stu2.height = 160
fmt.Println(stu2.name,stu2.age,stu2.height)
切片slice
Go 語言切片是對陣列的抽象。
Go 陣列的長度不可改變,在特定場景中這樣的集合就不太適用,Go中提供了一種靈活,功能強悍的內建型別切片(“動態陣列”),與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。
- 使用var定義
- 定義空slice
- 使用:=定義
- 使用make來定義 make([]type,len,cap)
- apend 和 copy的使用
package main
/*
author:xiaomotong
file:slice
function:study slice for golang
*/
import "fmt"
func main(){
//定義切片的方式
//1、使用var定義
var s1 = []int{1,2,3};
printInfo(s1);
//2、定義空slice
var s2 []int
printInfo(s2);
//3、使用:=定義
ss := []int{3,4,5,6}
printInfo(ss);
//4、使用make來定義 make([]type,len,cap)
s3 := make([]int,2,3)
printInfo(s3);
//複製操作
s3[0] = 3
printInfo(s3);
//覆蓋整個slice
s1 = s3
printInfo(s1);
//apend 和 copy的使用
s3 = append(s3,6,7,8,9)
printInfo(s3);
//擴容
s4 := make([]int,len(s3),cap(s3) * 3)
copy(s4,s3)
printInfo(s4);
//s[2:]
println(s4[1:])
println(s4[:4])
println(s4[1:3])
fmt.Printf("s4[1:] = %v \n",s4[1:])
fmt.Printf("s4[:4] = %v \n",s4[:4])
fmt.Printf("s4[1:3] = %v \n",s4[1:3])
}
func printInfo(s[]int){
fmt.Printf("len = %d, cap = %d, slic = %v\n",len(s),cap(s),s);
}
範圍Range
Go 語言中 range 關鍵字用於 for 迴圈中迭代陣列(array)、切片(slice)、通道(channel)或集合(map)的元素。
在陣列和切片中它返回元素的索引和索引對應的值,在集合中返回 key-value 對。
- range 對於 陣列、切片
- 對於字串
- range對於map集合
- 佔位符_
package main
/*
author:xiaomotong
file:range
function:study range for golang
*/
import "fmt"
func main(){
//1、range 對於 陣列、切片
s := []string{"apple","pen"}
for i,value := range s{
fmt.Println(i,value)
}
//2、對於字串
for i,value := range "hello"{
fmt.Println(i,value)
}
//3、range對於map集合
m := map[string]string{"name":"xiaopang","age":"25"}
for i,value := range m{
fmt.Println(i,value)
}
//4、佔位符_
sum := 0
nums := []int{1,2,3,4,5}
for _,value := range nums{
sum += value
}
fmt.Println(sum)
}
MAP集合
Map 是一種無序的鍵值對的集合。Map 最重要的一點是通過 key 來快速檢索資料,key 類似於索引,指向資料的值。
Map 是一種集合,所以我們可以像迭代陣列和切片那樣迭代它。不過,Map 是無序的,我們無法決定它的返回順序,這是因為 Map 是使用 hash 表來實現的。
//類似於key-value的形式
map[string]string
m := map[string]string{"name":"xiaozhu","age":"15"}
mm := make(map[string]string)
countryCapitalMap [ "France" ] = "巴黎"
countryCapitalMap [ "Italy" ] = "羅馬"
countryCapitalMap [ "Japan" ] = "東京"
countryCapitalMap [ "India " ] = "新德里"
delete() 函式
delete() 函式用於刪除集合的元素, 引數為 map 和其對應的 key
delete(countryCapitalMap,"France")
遞迴函式
Go 語言支援遞迴。但我們在使用遞迴時,開發者需要設定退出條件,否則遞迴將陷入無限迴圈中。
遞迴函式對於解決數學上的問題是非常有用的,就像計算階乘,生成斐波那契數列等。
遞迴算階乘
package main
import "fmt"
func fabulaxiaomotong(n uint 64) (result uint64){
if n>0 {
return fabulaxiaomotong(n-1)*n
}
return 1
}
func main(){
fmt.Println("result : ",fabulaxiaomotong(15))
}
菲波拉契數列
func fabolaxiaomotong(n uint64)(result utin64){
if n<2{
return n
}else{
return fabolaxiaomotong(n-2)+fabolaxiaomotong(n-1)
}
}
介面
Go 語言提供了另外一種資料型別即介面,它把所有的具有共性的方法定義在一起,任何其他型別只要實現了這些方法就是實現了這個介面
package main
import "fmt"
//介面
type phone interface {
call()
show()
}
type xiaomi struct {
name string
ads string
}
type huawei struct {
name string
ads string
}
//介面實現
func (x xiaomi) call() {
fmt.Println("phoneName :", x.name)
}
func (x xiaomi) show() {
fmt.Println("advertisement :", x.ads)
}
func (h huawei) call() {
fmt.Println("phoneName :", h.name)
}
func (h huawei) show() {
fmt.Println("advertisement :", h.ads)
}
func main() {
x := xiaomi{"mi note2", "for fire"}
x.call()
x.show()
h := huawei{"hw p40", "your better phone"}
h.call()
h.show()
}
錯誤
Go 語言通過內建的錯誤介面提供了非常簡單的錯誤處理機制。error型別是一個介面型別,這是它的定義:
package main
import "fmt"
//定義資料結構
type DivideError struct {
devidee int
devider int
}
//錯誤處理實現Error()介面
func (de *DivideError) Error() string {
strdata := `
error,divide is zero
dividee is %d
divider is zero
`
return fmt.Sprintf(strdata, de.devidee)
}
//實現功能介面
func Divide(dividee int, divider int) (result int, errMsg string) {
if divider == 0 {
data := DivideError{dividee, divider}
errMsg = data.Error()
return
} else {
return dividee / divider, ""
}
}
func main() {
a := 10
b := 0
result, err := Divide(a, b)
if err != "" {
fmt.Println(err)
return
}
fmt.Printf("%d / %d == %d \n", a, b, result)
}
go語言的併發
Go 語言支援併發,我們只需要通過 go 關鍵字來開啟 goroutine 即可。goroutine 是輕量級執行緒,goroutine 的排程是由 Golang 執行時進行管理的。goroutine 語法格式:
- go的併發也是執行緒不安全的,需要加鎖才安全
package main
import (
"fmt"
"time"
)
func say(s string) {
var i int
for i = 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
var num int = 0
//goroutine 是執行緒不安全的
func countNum() {
var i int
for i = 0; i < 10; i++ {
time.Sleep(5 * time.Millisecond)
num++
}
}
func main() {
//go say("hello")
//say("world")
go countNum()
countNum()
fmt.Println(num)
}
通道(channel)
通道(channel)是用來傳遞資料的一個資料結構。通道可用於兩個 goroutine 之間通過傳遞一個指定型別的值來同步執行和通訊。操作符 <- 用於指定通道的方向,傳送或接收。如果未指定方向,則為雙向通道。
- 注意:預設情況下,通道是不帶緩衝區的。傳送端傳送資料,同時必須有接收端相應的接收資料。以下例項通過兩個 goroutine 來計算數字之和,在 goroutine 完成計算後,它會計算兩個結果的和:
通道可以設定緩衝區,通過 make 的第二個引數指定緩衝區大小
Go 通過 range 關鍵字來實現遍歷讀取到的資料,類似於與陣列或切片
package main
import "fmt"
//不帶緩衝的 通道
func getSum(s []int, c chan int) {
sum := 0
for _, value := range s {
sum += value
}
c <- sum
}
func getSum2(c chan int, n int) {
x, y := 0, 1
var i int
for i = 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c) //關閉通道
}
func main() {
//不帶緩衝的 通道
// s := []int{3, 5, -2, 3, 4, 7, 1, 1, 1}
// c := make(chan int)
// go getSum(s[:3], c)
// go getSum(s[3:6], c)
// go getSum(s[6:], c)
// x, y, z := <-c, <-c, <-c
// fmt.Println(x, y, z, x+y+z)
//帶緩衝的通道
c := make(chan int, 10)
go getSum2(c, cap(c))
for value := range c {
fmt.Println(value)
}
}
自己呼叫別的包/自己的包
自己呼叫別人的包或者自己的包,如上目錄結構
- 自己寫的包名,要和目錄名一樣
- 使用go mod 模組 ,執行 go mod init mystudy
mylib.go
package mylib
func Add(a, b int) int {
return a + b
}
main.go
package main
import (
"fmt"
"mystudy/mylib"
)
func main() {
fmt.Println(mylib.Add(2, 3))
}
以上為本期全部內容,如有疑問可以在評論區或後臺提出你的疑問,我們一起交流,一起成長。
好傢伙要是文章對你還有點作用的話,請幫忙點個關注,分享到你的朋友圈,分享技術,分享快樂
技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。
作者:小魔童哪吒
本作品採用《CC 協議》,轉載必須註明作者和本文連結