GO基础知识分享

兵长:哟,最近在干啥呢

胖sir:在看我之前的go基础学习资料呢,回顾一下

兵长:那给我分享一下呗,我也想回顾回顾

胖sir:用你的小手指点开你的手机,我来传给你

兵长:你信不信我的小手指可以带你飞整个峡谷 . . .

go语言的基本事项
  1. go run hello.go 直接运行,输出结果(原理也是编译后执行)

  2. go build hello.go 生成可执行程序,运行可执行程序,输出结果

  3. 注意 go语言中花括号不能单独占一行,否则会报错

1package main23import "fmt"45func main(){ //go语言中此处的花括号不能单独占一行,否则会报错6    fmt.Println("hello world")7}
  1. go语言一条语句占一行,如果一行需要执行多个语句 使用 分号 隔开

  2. go语言的输出语句有3种方式

  3. 1. import "fmt" 后适用fmt.Println(x) -- 输出

  4. println(x) -- 输出

  5. fmt.Printf("%d",x) -- 格式化输出

关键字

下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

breakdefaultfuncinterfaceselectcasedefergomapstructchanelsegotopackageswitchconstfallthroughifrangetypecontinueforimportreturnvar

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

appendboolbytecapclosecomplexcomplex64complex128uint16copyfalsefloat32float64imagintint8int16uint32int32int64iotalenmakenewnilpanicuint64printprintlnrealrecoverstringtrueuintuint8uintptr

字符串的拼接和变量的定义方式

定义变量的三种方式

  1. 正常使用var定义变量

  2. 使用var定义变量,但是不定义类型,通过赋初值的方式,go编译器自动识别

  3. 使用:=的方式来进行 新变量的定义,仅限于新变量 -- 适用于定义在函数内部

 1//字符串 可以使用+ 进行拼接 2    fmt.Println("this is my func") 3    fmt.Println("hello ,wolrd" + "xiaozhuzhu") 4 5//定义变量 6    var  name string="xiaomotong" 7    var age,tail int=24,170 8    fmt.Println(name, age , tail) 9    fmt.Println(name)10    fmt.Println(age)11    fmt.Println(tail)1213//定义变量的三种方式14//115    var a int = 116    fmt.Println(a)1718//2 使用var定义变量,但是不定义类型,通过赋初值的方式,go编译器自动识别19    var b = "hello"20    fmt.Println(b)2122//3 使用:=的方式来进行 新变量的定义,仅限于新变量 23//:= 左侧如果没有声明新的变量,就产生编译错误24    c := 2025    fmt.Println(c)26    //c:=30 //报错,因为c已经不是新变量的27    c=30    //正确,是一个正常的赋值操作28    fmt.Println(c)2930    c,d:=40,90 //这样是合法的31    fmt.Println(c,d)

因式分解的方式,仅仅适用于定义全局变量

1//因式分解的方式,仅仅适用于定义全局变量2var3(4    g_a int = 15    g_b,g_c int=1,26)
空白符

空白标识符 _ 也被用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。

_ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。

1//空白符2    _,e := 2,33    fmt.Println(e)
const常量
  • 定义const常量

1//定义const常量2    const width,height = 10,53    var area int=width*height4    fmt.Println("面积为", area)  //50
  • const常量用作枚举

1const(2    unknow = 03    man = 14    woman = 25)67println(unknow,man,woman)  //0 1 2
  • 常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:

1const(2    a = "hello"3    b = len(a)4    c = unsafe.Sizeof(a)5)6println(a,b,c)  //hello 5 16
iota的用法

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值:

 1//itoa的用法 2const( 3    g_a = iota 4    g_b 5    g_c 6    g_d 7) 8 9const(10    g_e = iota11    g_f = "hello"12    g_g13    g_h = iota14    g_i15)1617const(18    g_j = 1<
运算符

go语言的运算符和C语言的运算符基本一致

Go 没有三目运算符,不能适用?:

算术运算符

关系运算符

逻辑运算符

位运算符

赋值运算符

其他运算符

语言条件语句
  • if xxx

1if xxx {2    ...3}
  • if xxx {…} else{…}

1if xxx{2    ...3}else{4    ...5}
  • if xxx{ … if xxx { …}}

1if xxx{2    if xxx {3        ...4    }5    ...6}
  • switch

 1package main 2 3import "fmt" 4 5func main(){ 6 7    grade:= 90 8    if grade >= 90{ 9        println("优秀")10    }else if grade >=70 && grade <90{11        println("良好")12    }else{13        println("差")14    }1516    var x interface{} //计算类型1718    switch i := x.(type){19        case nil:20        fmt.Printf(" x 的类型 :%T\n",i)21        case int:22        fmt.Printf("x 是 int 型")23        default:24        println("未知")25    }26}
  • select

    类似于C语言中的select,用于多路IO复用

for循环的方式
  • 三种方式

  1. 类似C语言中的for

  2. 类似C语言中的while

  3. 死循环

 1package main 2 3import "fmt" 4 5func main(){ 6 7//类似C语言中的for 8    var sum int 9    for i:=1;i<=10;i++{10        sum +=i11    }1213    fmt.Println(sum)141516//类似于while17    for sum >30{18        sum -= 1019        fmt.Println(sum)20    }2122//死循环2324for {25    ...26}
  • For-each range 循环

 1//for-each  range 循环的方式 2    name := []string{"qqq","yyy"} 3    for i,str:= range name{ 4    fmt.Printf("%d -- %s\n",i,str) 5    } 6 7//0 -- qqq 8//1 -- yyy 9------------------------------------------------------------------------10    str := []string{"北京", "天津", "山东"}1112    //可以默认丢掉第二个返回值13    for i := range str {14        fmt.Printf("%d -- %s\n", i, str[i])15    }
函数

go语言的函数,可以有多个返回值,其余和C语言没有什么区别

作用域

与C语言一致

  • 局部变量

  • 全局变量

  • 函数形参

数组&切片

思想和C语言一致,数组是固定长度的

切片是动态扩容的,类似于C++的vector

切片写法如下:

1name := []string{"xiaomotong","pangsir"}23nums :=[]int{1,2,3,4,5,6}
指针
1var ptr1 *int
二级指针
1var  a int2var ptr *int3var pptr **int45ptr = &a6pptr = &ptr
指针数组
1var ptr [5]*int
结构体

go语言中的结构体变量,和结构体指针,访问结构体成员的时候,都是使用 点(.)来进行访问,如下:

 1//定义一个结构体 2type info struct{ 3    name string 4    age int 5    height int 6} 7 8//使用 9var stu info10stu.name = "xiaomotong"11stu.age = 2412stu.height = 1701314fmt.Println(stu.name,stu.age,stu.height)1516var stu2 *info = &stu17stu2.name = "pangsir"18stu2.age = 2419stu2.height = 1602021fmt.Println(stu2.name,stu2.age,stu2.height)
切片slice

Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

  • 使用var定义

  • 定义空slice

  • 使用:=定义

  • 使用make来定义 make([]type,len,cap)

  • apend 和 copy的使用

 1package main 2 3/* 4    author:xiaomotong 5    file:slice 6    function:study slice for golang 7*/ 8import "fmt" 91011func main(){12//定义切片的方式13//1、使用var定义14    var s1 = []int{1,2,3};15    printInfo(s1);16//2、定义空slice17    var s2 []int18    printInfo(s2);19//3、使用:=定义20    ss := []int{3,4,5,6}21    printInfo(ss);2223//4、使用make来定义 make([]type,len,cap)24    s3 := make([]int,2,3)25    printInfo(s3);26//复制操作27    s3[0] = 328    printInfo(s3);29//覆盖整个slice30    s1 = s331    printInfo(s1);3233//apend 和 copy的使用34    s3 = append(s3,6,7,8,9)35    printInfo(s3);36//扩容37    s4 := make([]int,len(s3),cap(s3) * 3)38    copy(s4,s3)39    printInfo(s4);40//s[2:]41    println(s4[1:])42    println(s4[:4])43    println(s4[1:3])44    fmt.Printf("s4[1:] = %v \n",s4[1:])45    fmt.Printf("s4[:4] = %v \n",s4[:4])46    fmt.Printf("s4[1:3] = %v \n",s4[1:3])47}4849func printInfo(s[]int){50    fmt.Printf("len = %d, cap = %d, slic = %v\n",len(s),cap(s),s);5152}
范围Range

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。

在数组和切片中它返回元素的索引和索引对应的值在集合中返回 key-value 对

  • range 对于 数组、切片

  • 对于字符串

  • range对于map集合

  • 占位符_

 1package main 2 3/* 4    author:xiaomotong 5    file:range 6    function:study range for golang 7*/ 8import "fmt" 91011func main(){1213//1、range 对于 数组、切片1415    s := []string{"apple","pen"}16    for i,value := range s{17        fmt.Println(i,value)18    }1920//2、对于字符串21    for i,value := range "hello"{22        fmt.Println(i,value)23    }2425//3、range对于map集合26    m := map[string]string{"name":"xiaopang","age":"25"}27    for i,value := range m{28        fmt.Println(i,value)29    }3031//4、占位符_32    sum := 033    nums := []int{1,2,3,4,5}34    for _,value := range nums{35        sum += value36    }37    fmt.Println(sum)38}
MAP集合

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

 1//类似于key-value的形式 2map[string]string 3 4m := map[string]string{"name":"xiaozhu","age":"15"} 5 6mm := make(map[string]string) 7 8countryCapitalMap [ "France" ] = "巴黎" 9countryCapitalMap [ "Italy" ] = "罗马"10countryCapitalMap [ "Japan" ] = "东京"11countryCapitalMap [ "India " ] = "新德里"
delete() 函数

delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key

1delete(countryCapitalMap,"France")
递归函数

Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。

递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等。

递归算阶乘

 1package main 2 3import "fmt" 4 5func fabulaxiaomotong(n uint 64) (result uint64){ 6    if n>0 { 7        return fabulaxiaomotong(n-1)*n 8    } 9    return 110}1112func main(){13    fmt.Println("result : ",fabulaxiaomotong(15))14}

菲波拉契数列

1func fabolaxiaomotong(n uint64)(result utin64){2    if n<2{3        return n4    }else{5        return fabolaxiaomotong(n-2)+fabolaxiaomotong(n-1)6    }7}
接口

Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口

 1package main 2 3import "fmt" 4 5//接口 6type phone interface { 7    call() 8    show() 9}1011type xiaomi struct {12    name string13    ads  string14}1516type huawei struct {17    name string18    ads  string19}2021//接口实现22func (x xiaomi) call() {23    fmt.Println("phoneName :", x.name)24}2526func (x xiaomi) show() {27    fmt.Println("advertisement :", x.ads)28}2930func (h huawei) call() {31    fmt.Println("phoneName :", h.name)32}3334func (h huawei) show() {35    fmt.Println("advertisement :", h.ads)36}3738func main() {39    x := xiaomi{"mi note2", "for fire"}40    x.call()41    x.show()4243    h := huawei{"hw p40", "your better phone"}44    h.call()45    h.show()46}
错误

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。error类型是一个接口类型,这是它的定义:

 1package main 2 3import "fmt" 4 5//定义数据结构 6type DivideError struct { 7    devidee int 8    devider int 9}1011//错误处理实现Error()接口12func (de *DivideError) Error() string {13    strdata := `14        error,divide is zero15        dividee is %d16        divider is zero17    `1819    return fmt.Sprintf(strdata, de.devidee)20}2122//实现功能接口23func Divide(dividee int, divider int) (result int, errMsg string) {24    if divider == 0 {25        data := DivideError{dividee, divider}26        errMsg = data.Error()27        return28    } else {29        return dividee / divider, ""30    }31}3233func main() {34    a := 1035    b := 036    result, err := Divide(a, b)37    if err != "" {38        fmt.Println(err)39        return40    }41    fmt.Printf("%d / %d == %d \n", a, b, result)4243}
go语言的并发

Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。goroutine 语法格式:

  • go的并发也是线程不安全的,需要加锁才安全

 1package main 2 3import ( 4    "fmt" 5    "time" 6) 7 8func say(s string) { 9    var i int10    for i = 0; i < 5; i++ {11        time.Sleep(100 * time.Millisecond)12        fmt.Println(s)13    }14}1516var num int = 01718//goroutine 是线程不安全的19func countNum() {20    var i int21    for i = 0; i < 10; i++ {22        time.Sleep(5 * time.Millisecond)23        num++24    }25}26func main() {27    //go say("hello")28    //say("world")2930    go countNum()31    countNum()32    fmt.Println(num)33}
通道(channel)
  • 通道(channel)是用来传递数据的一个数据结构。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

  • 注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。以下实例通过两个 goroutine 来计算数字之和,在 goroutine 完成计算后,它会计算两个结果的和:

  • 通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小

  • Go 通过 range 关键字来实现遍历读取到的数据,类似于与数组或切片

 1package main 2 3import "fmt" 4 5//不带缓冲的 通道 6func getSum(s []int, c chan int) { 7    sum := 0 8    for _, value := range s { 9        sum += value10    }11    c <- sum12}1314func getSum2(c chan int, n int) {15    x, y := 0, 116    var i int17    for i = 0; i < n; i++ {18        c <- x19        x, y = y, x+y20    }21    close(c) //关闭通道22}2324func main() {25    //不带缓冲的 通道26    // s := []int{3, 5, -2, 3, 4, 7, 1, 1, 1}27    // c := make(chan int)28    // go getSum(s[:3], c)29    // go getSum(s[3:6], c)30    // go getSum(s[6:], c)31    // x, y, z := <-c, <-c, <-c32    // fmt.Println(x, y, z, x+y+z)3334//带缓冲的通道35    c := make(chan int, 10)36    go getSum2(c, cap(c))3738    for value := range c {39        fmt.Println(value)40    }4142}
自己调用别的包/自己的包

自己调用别人的包或者自己的包,如上目录结构

  • 自己写的包名,要和目录名一样

  • 使用go mod 模块 ,执行 go mod init mystudy

mylib.go

1package mylib23func Add(a, b int) int {4    return a + b5}

main.go

 1package main 2 3import ( 4    "fmt" 5    "mystudy/mylib" 6) 7 8func main() { 9    fmt.Println(mylib.Add(2, 3))10}

以上为本期全部内容,如有疑问可以在评论区或后台提出你的疑问,我们一起交流,一起成长。

好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享快乐

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。