[TOC]

GO基础知识分享

兵长:哟,最近在干啥呢

胖sir:在看我之前的go根底学习材料呢,回顾一下

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

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

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

go语言的根本事项

  1. go run hello.go 间接运行,输入后果(原理也是编译后执行)
  2. go build hello.go 生成可执行程序,运行可执行程序,输入后果
  3. 留神 go语言中花括号不能独自占一行,否则会报错
package mainimport "fmt"func main(){ //go语言中此处的花括号不能独自占一行,否则会报错    fmt.Println("hello world")}
  1. go语言一条语句占一行,如果一行须要执行多个语句 应用 分号 隔开
  2. go语言的输入语句有3种形式
    1. import "fmt" 后实用fmt.Println(x) -- 输入
    2. println(x) -- 输入
    3. fmt.Printf("%d",x) -- 格式化输入

关键字

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

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

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

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

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

定义变量的三种形式

  1. 失常应用var定义变量
  2. 应用var定义变量,然而不定义类型,通过赋初值的形式,go编译器自动识别
  3. 应用:=的形式来进行 新变量的定义,仅限于新变量 -- 实用于定义在函数外部
//字符串 能够应用+ 进行拼接    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 mainimport "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循环的形式

  • 三种形式
  1. 相似C语言中的for
  2. 相似C语言中的while
  3. 死循环
package mainimport "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 intvar ptr *intvar pptr **intptr = &apptr = &ptr

指针数组

var ptr [5]*int

构造体

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

//定义一个构造体type info struct{    name string    age int    height int}//应用var stu infostu.name = "xiaomotong"stu.age = 24stu.height = 170fmt.Println(stu.name,stu.age,stu.height)var stu2 *info = &stustu2.name = "pangsir"stu2.age = 24stu2.height = 160fmt.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]stringm := 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 mainimport "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 mainimport "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 mainimport "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 mainimport (    "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 mainimport "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 mylibfunc Add(a, b int) int {    return a + b}

main.go

package mainimport (    "fmt"    "mystudy/mylib")func main() {    fmt.Println(mylib.Add(2, 3))}

以上为本期全部内容,如有疑难能够在评论区或后盾提出你的疑难,咱们一起交换,一起成长。

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

技术是凋谢的,咱们的心态,更应是凋谢的。拥抱变动,背阴而生,致力向前行。

作者:小魔童哪吒