GO基础知识分享
兵长:哟,最近在干啥呢
胖sir:在看我之前的go基础学习资料呢,回顾一下
兵长:那给我分享一下呗,我也想回顾回顾
胖sir:用你的小手指点开你的手机,我来传给你
兵长:你信不信我的小手指可以带你飞整个峡谷 . . .
go语言的基本事项go run hello.go 直接运行,输出结果(原理也是编译后执行)
go build hello.go 生成可执行程序,运行可执行程序,输出结果
注意 go语言中花括号不能单独占一行,否则会报错
1package main23import "fmt"45func main(){ //go语言中此处的花括号不能单独占一行,否则会报错6 fmt.Println("hello world")7}
go语言一条语句占一行,如果一行需要执行多个语句 使用 分号 隔开
go语言的输出语句有3种方式
1. import "fmt" 后适用fmt.Println(x) -- 输出
println(x) -- 输出
fmt.Printf("%d",x) -- 格式化输出
下面列举了 Go 代码中会使用到的 25 个关键字或保留字:
breakdefaultfuncinterfaceselectcasedefergomapstructchanelsegotopackageswitchconstfallthroughifrangetypecontinueforimportreturnvar
除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:
appendboolbytecapclosecomplexcomplex64complex128uint16copyfalsefloat32float64imagintint8int16uint32int32int64iotalenmakenewnilpanicuint64printprintlnrealrecoverstringtrueuintuint8uintptr
字符串的拼接和变量的定义方式定义变量的三种方式
正常使用var定义变量
使用var定义变量,但是不定义类型,通过赋初值的方式,go编译器自动识别
使用:=的方式来进行 新变量的定义,仅限于新变量 -- 适用于定义在函数内部
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复用
三种方式
类似C语言中的for
类似C语言中的while
死循环
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)
切片sliceGo 语言切片是对数组的抽象。
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}
范围RangeGo 语言中 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}
以上为本期全部内容,如有疑问可以在评论区或后台提出你的疑问,我们一起交流,一起成长。
好家伙要是文章对你还有点作用的话,请帮忙点个关注,分享到你的朋友圈,分享技术,分享快乐
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。