还剩28页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
语言编程教学课件Go语言简介Go语言(也称为)由公司的、和于年开始设计,并于年正式发布Go GolangGoogle RobertGriesemer RobPike KenThompson20072009作为一种开源的编程语言,语言旨在提高大型软件系统的开发效率Go语言的设计理念是Go简洁语法简单明了,减少复杂性和冗余•高效编译速度快,运行性能接近•C/C++安全内置垃圾回收,减少内存错误•并发从语言层面支持并发编程•语言结合了低级语言的性能与高级语言的开发效率,在保持静态类型和编译型语言特性的同时,提供了类似动态语言的开发体验它不仅Go完全开源,而且拥有跨平台支持,可以在、和各种系统上运行Windows MacOS Linux/Unix语言的吉祥物是一只名为的地鼠,象征着这门语言的简单友好和高效挖掘解决问题的能力语言的设计目标是创建一种适合现Go GopherGo代多核计算机和网络环境的编程语言,同时避免其他语言中的复杂性年
142.4M+发展历史开发者自年发布以来的持续发展时间全球语言活跃开发者数量2009Go200K+语言应用场景Go云计算与微服务网络服务器与分布式系统命令行工具与自动化脚本语言在云计算领域取得了巨大成功,语言为构建高性能网络服务器提供了语言编译生成的是静态二进制文件,Go Go Go最著名的例子是容器编排平台出色的支持,标准库中的包使无需解释器或运行时依赖,使其成为开net/http和容器化技术,这开发服务变得简单高效许多公发命令行工具和自动化脚本的绝佳选择Kubernetes DockerHTTP两个项目彻底改变了现代应用部署方式司使用构建服务器、应用后单一可执行文件便于分发和部署,跨平Go APIWeb语言的高并发性能和低资源占用使其端和大规模分布式系统,能够轻松处理台支持使开发者能够轻松构建在不同操Go成为微服务架构的理想选择,能够高效高并发负载作系统上运行的工具处理大量并发请求现代反向代理和负世界上最快的静态网站生成•Traefik HTTP•Hugo容器编排平台,管理载均衡器器•Kubernetes分布式应用具有自动功能的监控系统和时间序•Caddy HTTPS•Prometheus容器化平台,简化应用部服务器列数据库•Docker Web署分布式键值存储,用于配置基础设施即代码工具•etcd•Terraform服务网格,管理微服务通信管理•Istio开发环境搭建概览语言环境搭建相对简单,官方提供了完整的安装包和详细的文档无论您使用何种操作系统,都可以轻松配置开发环境以下是开发环Go Go境搭建的基本步骤和注意事项下载安装包访问语言官方网站或中国镜像站,下载适合您操作系统的安装包提供了、和Go golang.org golang.google.cn Go Windows MacOS等各种平台的安装包Linux安装语言Go按照官方指南安装语言用户运行安装文件,用户可以使用安装包或,用户可以使用GoWindowsMSI MacOSpkg HomebrewLinux包管理器或包安装tar配置环境变量设置(工作目录)和(安装目录)环境变量,并将的目录添加到环境变量中,使命令可以GOPATH GOROOTGoGobin PATHGo在任何目录下执行选择并配置IDE选择适合的开发工具,如、或等,安装相关语言插件,配置代码补全、格式化和调试功能VSCode GoLandLiteIDE Go推荐的开发工具轻量级、免费、功能强大的编辑器,搭配插件使用Visual StudioCode Go开发的专业,功能全面但需付费GoLand JetBrainsGo IDE专为语言设计的开源集成开发环境LiteIDE Go配合插件使用的传统文本编辑器,适合命令行爱好者Vim/Neovim Go高性能文本编辑器,通过插件支持开发Sublime TextGo验证安装完成安装后,打开命令行终端,输入go version命令检查安装是否成功如果显示版本信息,说明安装成功Go环境安装配置Windows系统语言安装步骤Windows Go
1.访问官方网站golang.org/dl/下载Windows版Go安装包(.msi文件)
2.双击MSI文件运行安装向导,按照提示完成安装
3.默认安装路径通常为C:\Go,建议使用默认设置
4.安装程序会自动将Go添加到PATH环境变量中环境变量配置Go语言在Windows系统上需要配置以下关键环境变量GOROOT指向Go语言安装目录,通常为C:\GoGOPATH指向您的Go工作空间,推荐设置为%USERPROFILE%\goPATH需要包含%GOROOT%\bin和%GOPATH%\bin目录配置环境变量的步骤
1.右键点击此电脑或我的电脑,选择属性
2.点击高级系统设置,然后点击环境变量按钮
3.在系统变量部分,添加或修改GOROOT和GOPATH
4.编辑PATH变量,确保包含Go的bin目录验证安装打开命令提示符cmd或PowerShell,输入以下命令验证Go是否安装成功与安装配置MacOSLinux系统安装MacOS Go在MacOS系统上,有多种方式安装Go语言方法一使用安装(推荐)HomebrewHomebrew是MacOS上流行的包管理工具,使用它安装Go非常简便
1.打开终端应用
2.如果尚未安装Homebrew,请先安装/bin/bash-c$curl-fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh
1.使用Homebrew安装Go brewinstall go方法二使用官方安装包
1.访问golang.org下载MacOS安装包(.pkg文件)
2.双击pkg文件运行安装向导
3.按照提示完成安装方法二使用官方二进制包(推荐,获取最新版本)系统安装Linux Go
1.下载最新的Go二进制包在Linux系统上安装Go的常用方法方法一使用包管理器wget https://golang.org/dl/go
1.
20.
1.linux-amd
64.tar.gzUbuntu/Debian
1.解压到/usr/local目录sudo aptupdatesudo aptinstall golang-go sudotar-C/usr/local-xzf go
1.
20.
1.linux-amd
64.tar.gz环境变量配置CentOS/RHEL/Fedora在MacOS和Linux系统上,需要配置以下环境变量sudo dnfinstall golang编辑~/.bashrc或~/.zshrc文件(取决于您使用的shell),添加以下内容export GOROOT=/usr/local/go#或Homebrew安装位置export GOPATH=$HOME/goexport PATH=$PATH:$GOROOT/bin:$GOPATH/bin使环境变量生效source~/.bashrc#或source~/.zshrc验证安装第一个程序Go Hello World程序的基本结构Go每个Go源文件都以包声明开始,指定该文件属于哪个包可执行程序必须包含一个名为main的包和一个main函数,这是程序的入口点以下是一个最简单的Go程序-HelloWorld//hello.gopackage mainimport fmtfunc main{fmt.Println你好,世界!}代码解析package main声明这个文件属于main包,表示这是一个可执行程序而非库import fmt导入fmt包,它提供格式化输入输出的功能func main定义main函数,程序从这里开始执行fmt.Println调用fmt包中的Println函数打印文本到控制台编译与运行Go提供了多种方式编译和运行程序方法一直接运行go runhello.go这个命令会编译并立即运行程序,适合开发阶段使用方法二编译成可执行文件go buildhello.go这个命令会编译程序并生成一个可执行文件在Windows上生成hello.exe,在MacOS/Linux上生成hello基础语法变量声明与赋值变量声明方式Go语言提供了多种变量声明和初始化的方法使用关键字声明
1.var//基本语法var变量名类型//示例var name stringvar age intvar isActivebool声明并初始化
2.//声明变量并赋初值var namestring=张三var ageint=25var salary float64=
5000.50//类型推断(省略类型)var name=张三//编译器自动推断为string类型var age=25//编译器自动推断为int类型基本数据类型类型分类具体类型说明短变量声明()
3.:=这是在函数内部最常用的声明方式整数类型int根据系统架构,32位或64位int88位有符号整数-128到127//短变量声明,只能在函数内部使用name:=张三age:=25isActive:=trueint1616位有符号整数int32/rune32位有符号整数
4.多变量声明int6464位有符号整数无符号整数uint根据系统架构,32位或64位//一次声明多个同类型变量var i,j,k int//一次声明多个不同类型变量varnamestringageintsalaryfloat64//多变量声明并初始化var i,j,k int=1,2,3var name,age=张三,25//短变量形式name,age:=张三,25uint8/byte8位无符号整数0到255uint1616位无符号整数uint3232位无符号整数uint6464位无符号整数浮点数float3232位浮点数常量与枚举模拟常量声明常量是在编译时就确定的值,运行期间不能修改Go使用const关键字声明常量//基本语法const常量名类型=值//示例const Pifloat64=
3.14159const MaxConnections=1000const Greeting=你好//类型可以省略,由编译器推断const Pi=
3.14159const MaxConnections=1000常量组多个常量可以一起声明在一个const块中constPi=
3.14159E=
2.71828StatusOK=200StatusNotFound=404Prefix=GO_无类型常量Go的常量可以是无类型的(untyped),这使它们更加灵活constPi=
3.14159//无类型浮点常量Size=100//无类型整型常量Name=Go//无类型字符串常量var ffloat32=Pi//合法,Pi可以赋值给float32var iint=Size//合法,Size可以赋值给int与枚举iotaGo语言没有内置的枚举类型,但可以使用iota标识符来模拟枚举iota在const块中会自动递增constSunday=iota//0Monday//1Tuesday//2Wednesday//3Thursday//4Friday//5Saturday//6运算符与表达式算术运算符运算符描述示例+加法a+b-减法a-b*乘法a*b/除法a/b%取模(余数)a%b关系运算符运算符描述示例==等于a==b!=不等于a!=b大于ab小于ab=大于等于a=b位运算符=小于等于a=b运算符描述示例逻辑运算符按位与ab运算符描述示例|按位或a|b逻辑与ab^按位异或a^b||逻辑或a||b左移an!逻辑非!a右移an^位清除(AND NOT)a^b赋值运算符运算符描述等价形式=简单赋值a=b控制结构分支语句语句ifGo语言的if语句不需要圆括号,但花括号是必须的//基本形式if条件表达式{//条件为true时执行的代码}//示例if age=18{fmt.Println成年人}语句if-else//if-else基本形式if条件表达式{//条件为true时执行的代码}else{//条件为false时执行的代码}//示例if score=60{fmt.Println及格}else{fmt.Println不及格}带初始化语句的ifGo语言的if语句支持在条件判断之前执行一个简单的语句//基本形式if初始化语句;条件表达式{//条件为true时执行的代码}//示例if err:=doSomething;err!=nil{//处理错误fmt.Println发生错误:,err}语句if-else if-else//多条件判断if条件表达式1{//条件1为true时执行的代码}else if条件表达式2{//条件2为true时执行的代码}else if条件表达式3{//条件3为true时执行的代码}else{//所有条件都为false时执行的代码}//示例if score=90{fmt.Println优秀}else ifscore=75{fmt.Println良好}else ifscore=60{fmt.Println及格}else{fmt.Println不及格}这种形式非常适合处理函数返回的错误,变量err的作用域仅限于if语句块内语句switchGo的switch语句比其他语言更灵活,case无需break(默认自动break),多个条件可以用逗号分隔//基本形式switch表达式{case值1://代码1case值2,值3://代码2default://默认代码}//示例switch day{case星期一:fmt.Println开始工作了case星期六,星期日:fmt.Println周末休息default:fmt.Println工作日}控制结构循环语句循环forGo语言中只有一种循环结构for循环但它有多种形式,几乎可以实现所有循环需求标准循环
1.for//基本语法for初始化语句;条件表达式;后置语句{//循环体}//示例for i:=0;i5;i++{fmt.Printlni}//输出:01234类似的循环
2.while for//基本语法for条件表达式{//循环体}//示例i:=0for i5{fmt.Printlni i++}//输出:01234遍历rangeGo提供了range关键字,用于遍历数组、切片、字符串、map和通道遍历数组或切片
1.//基本语法for索引,值:=range集合{//使用索引和值}//示例nums:=[]int{10,20,30,40,50}for i,num:=range nums{fmt.Printf索引:%d值:%d\n,i,num}无限循环
3.//基本语法for{//循环体if条件{break//跳出循环}}//示例i:=0for{fmt.Printlni i++if i=5{break}}//输出:01234仅使用索引或值
2.//仅使用索引for i:=range nums{fmt.Printf索引:%d\n,i}//仅使用值for_,num:=range nums{fmt.Printf值:%d\n,num}数组与切片数组()Array数组是具有固定长度的一组同类型数据的集合数组声明与初始化
1.//声明数组var arr
[5]int//长度为5的整型数组,默认值都为0//声明并初始化var arr=
[5]int{1,2,3,4,5}//短变量声明arr:=
[5]int{1,2,3,4,5}//自动计算长度arr:=[...]int{1,2,3,4,5}//编译器自动计算长度为5//指定索引位置初始化arr:=
[5]int{0:10,2:30,4:50}//[10,0,30,0,50]多维数组
2.//二维数组声明var matrix
[3]
[4]int//二维数组初始化matrix:=
[3]
[4]int{{0,1,2,3},{4,5,6,7},{8,9,10,11},}切片()Slice切片是对数组的引用,是一个动态数组,长度可变切片声明与创建
1.//声明一个空切片var s[]int//长度为0的int切片,值为nil//使用make函数创建切片s:=make[]int,5//长度为5,容量为5的切片s:=make[]int,5,10//长度为5,容量为10的切片//通过数组切片创建arr:=
[5]int{1,2,3,4,5}s:=arr[1:4]//
[234],引用arr的部分元素//切片字面量s:=[]int{1,2,3,4,5}数组是值类型
3.在Go中,数组是值类型,赋值或传递给函数时会复制整个数组arr1:=
[3]int{1,2,3}arr2:=arr1//arr2是arr1的完整复制arr2
[0]=100//修改arr2不会影响arr1fmt.Printlnarr1//
[123]fmt.Printlnarr2//
[10023]切片操作
2.//切片追加元素s=appends,6//添加一个元素s=appends,7,8,9//添加多个元素s=appends,s
2...//添加另一个切片的所有元素//切片容量自动扩展s:=make[]int,0for i:=0;i10;i++{s=appends,i fmt.Printf长度:%d容量:%d\n,lens,caps}//切片的切片s:=[]int{1,2,3,4,5}s1:=s[1:3]//
[23]s2:=s[:]//
[12345],完整切片s3:=s[:3]//
[123],从开始到索引3(不含)s4:=s[2:]//
[345],从索引2到结束(字典)使用Map基础MapMap是Go语言中的哈希表实现,用于存储键值对声明与创建
1.Map//声明一个mapvar mmap[string]int//键类型为string,值类型为int,此时m为nil//使用make函数创建mapm=makemap[string]int//创建并初始化mapm:=map[string]int{苹果:5,香蕉:8,橙子:3,}map的键可以是任何可比较的类型,如布尔、数字、字符串、指针、通道以及仅包含这些类型的接口、结构体和数组不能使用切片、映射和函数作为键,因为它们不可比较基本操作
2.//添加或修改元素m[葡萄]=10m[苹果]=7//修改已有键的值//获取元素count:=m[苹果]//获取键苹果对应的值//判断键是否存在count,exists:=m[西瓜]if exists{fmt.Printf西瓜的数量是:%d\n,count}else{fmt.Println没有西瓜}//删除元素的遍历deletem,香蕉//从map中删除键香蕉及其对应的值Map使用range关键字可以遍历map中的键值对//遍历所有键值对for key,value:=range m{fmt.Printf%s:%d\n,key,value}//只遍历键for key:=range m{fmt.Printlnkey}//只遍历值for_,value:=range m{fmt.Printlnvalue}注意map的遍历顺序是随机的,每次遍历的顺序可能不同的特性与注意事项Map函数基础函数定义Go语言的函数使用func关键字定义//基本语法func函数名参数列表返回类型{//函数体return返回值}//示例简单函数func addaint,b int int{return a+b}//参数类型简写func adda,b intint{return a+b}//没有参数和返回值的函数func sayHello{fmt.Println你好,世界!}多返回值Go语言的函数可以返回多个值,这是一个非常有用的特性//多返回值函数func dividea,b float64float64,error{if b==0{return0,errors.New除数不能为零}return a/b,nil}//调用多返回值函数result,err:=divide10,2if err!=nil{fmt.Println错误:,err}else{fmt.Println结果:,result}命名返回值闭包与匿名函数匿名函数Go支持匿名函数,即没有函数名的函数//定义并立即调用匿名函数func{fmt.Println这是一个匿名函数}//带参数的匿名函数funcname string{fmt.Printf你好,%s\n,name}张三//将匿名函数赋值给变量add:=funca,b intint{return a+b}fmt.Printlnadd5,3//8闭包基础闭包是引用了外部变量的匿名函数即使外部函数已经返回,闭包仍然可以访问并修改这些变量//简单闭包示例func makeCounterfunc int{count:=0return funcint{count++return count}}//使用闭包counter:=makeCounterfmt.Printlncounter//1fmt.Printlncounter//2fmt.Printlncounter//3//创建新的计数器,互不影响counter2:=makeCounterfmt.Printlncounter2//1fmt.Printlncounter//4闭包应用实例函数工厂
1.//创建增量函数的工厂func makeAdderbaseint funcintint{return funcxintint{return base+x}}//使用函数工厂add5:=makeAdder5add10:=makeAdder10fmt.Printlnadd52//7fmt.Printlnadd102//12在这个例子中,makeCounter函数返回一个匿名函数,这个匿名函数可以访问并修改makeCounter函数中的count变量每次调用返回的函数,count都会增加,形成了一个简单的计数器指针基础指针概念指针是存储另一个变量内存地址的变量Go语言的指针简化了C/C++中的指针操作,提供了安全性的同时保留了灵活性指针的声明与使用//声明指针变量var p*int//声明一个指向int类型的指针,初始值为nil//获取变量的地址x:=10p=x//p现在指向变量x的内存地址//通过指针访问值(解引用)fmt.Println*p//10,输出p指向的值//通过指针修改值*p=20//修改p指向的值fmt.Printlnx//20,x的值也被修改指针的零值指针的零值是nil,表示指针不指向任何内存地址尝试解引用一个nil指针会导致运行时错误(panic)var p*int//p的值为nil//*p=10//错误空指针解引用会导致panic//安全使用指针的方式if p!=nil{*p=10}else{//处理nil指针的情况}指针与函数newGo提供了new函数用于创建指针//使用new函数创建指针p:=newint//分配内存,返回指向零值int的指针*p=10//设置值fmt.Println*p//10指针传递与值传递在函数调用时,Go默认使用值传递,意味着函数接收的是参数的副本使用指针可以实现引用传递的效果结构体与面向对象结构体基础结构体是Go中表示复合数据类型的主要方式,可以将不同类型的数据组合在一起//定义结构体type Personstruct{Name stringAge intGender stringAddress Address//嵌套结构体}type Addressstruct{City stringCountry string}//创建结构体实例//方法1按字段顺序提供值p1:=Person{张三,30,男,Address{北京,中国}}//方法2指定字段名(推荐,更清晰)p2:=Person{Name:李四,Age:25,Gender:女,Address:Address{City:上海,Country:中国,},}//方法3使用new函数(返回指针)p3:=newPersonp
3.Name=王五p
3.Age=35//方法4先声明,再赋值var p4Personp
4.Name=赵六p
4.Age=40结构体嵌入(组合)Go不支持传统的继承,但可以通过嵌入结构体实现类似的功能//定义基础结构体type Humanstruct{Name stringAge intGender string}//定义方法func hHuman Speak string{return fmt.Sprintf你好,我是%s,h.Name}//嵌入Human结构体type Studentstruct{Human//匿名字段,嵌入HumanSchool stringGrade int}//Student特有的方法func sStudent Studystring{return fmt.Sprintf%s正在学习,s.Name}//使用嵌入结构体student:=Student{Human:Human{Name:小明,Age:15,Gender:男,},School:实验中学,Grade:9,}//可以直接访问嵌入结构体的字段和方法fmt.Printlnstudent.Name//小明fmt.Printlnstudent.Speak//你好,我是小明fmt.Printlnstudent.Study//小明正在学习结构体方法Go中的方法是特殊的函数,它与特定类型关联通过定义方法,可以为结构体添加行为//值接收者的方法func pPerson GetInfostring{return fmt.Sprintf%s,%d岁,来自%s,p.Name,p.Age,p.Address.City}//指针接收者的方法(可以修改接收者)func p*Person SetAgeageint{p.Age=age}接口与多态接口基础接口是Go中实现多态的主要机制,它定义了一组方法集而不实现它们//定义接口type Speakerinterface{Speakstring}//实现接口的结构体1type Humanstruct{Name string}func hHumanSpeak string{return fmt.Sprintf%s说你好!,h.Name}//实现接口的结构体2type Dogstruct{Name string}func dDogSpeak string{return fmt.Sprintf%s说汪汪!,d.Name}//接口作为函数参数,实现多态func LetsSpeaker{fmt.Printlns.Speak}//使用多态human:=Human{Name:张三}dog:=Dog{Name:旺财}Lethuman//输出:张三说你好!Letdog//输出:旺财说汪汪!在Go中,接口的实现是隐式的只要一个类型实现了接口中的所有方法,它就自动满足该接口,不需要显式声明接口值空接口接口值由两部分组成具体类型和该类型的值这两部分称为接口的动态类型和动态值空接口(interface{})不包含任何方法,因此所有类型都实现了空接口var sSpeaker//接口值是nil(动态类型和动态值都是nil)fmt.Printf%T%v\n,s,s////给接口赋值s=Human{Name:张三//定义空接口type Anyinterface{}//使用空接口作为参数(可接受任何类型)func PrintAnyainterface{}{fmt.Printlna}//调用}fmt.Printf%T%v\n,s,s//main.Human{张三}//更改接口值s=Dog{Name:旺财}fmt.Printf%T%v\n,s,s//main.Dog PrintAny42//整数PrintAny你好//字符串PrintAny[]int{1,2}//切片{旺财}错误处理机制错误处理基础Go语言使用显式的错误处理而不是异常机制函数通常返回一个错误值,调用者应该检查这个错误//error接口type errorinterface{Error string}//基本错误处理模式func doSomethingerror{//操作可能失败,返回错误if somethingFailed{return errors.New操作失败}return nil//成功时返回nil}//调用并处理错误err:=doSomethingif err!=nil{//处理错误fmt.Println发生错误:,err//可能返回错误或中止程序return}//继续执行...错误传递和包装创建错误Go
1.13引入了错误包装,允许在不丢失原始错误的情况下添加上下文Go提供了多种创建错误的方式//包装错误(Go
1.13+)func readConfigpathstring[]byte,error{data,err:=ioutil.ReadFilepath if err!=nil{return nil,fmt.Errorf读取配置文件失败:%w,err}return data,nil}//使用包装的错误data,err:=//使用errors包import errorserr1:=errors.New这是一个错误//使用fmt.Errorf格式化错误消息name:=文件err2:=readConfigconfig.jsonif err!=nil{//打印完整错误链fmt.Printlnerr//解包原始错误var pathErrfmt.Errorf%s不存在,name//自定义错误类型type MyErrorstruct{Code intMessage string}func eMyError Error*fs.PathError if errors.Aserr,pathErr{fmt.Printf文件操作错误:%v\n,pathErr.Path}//检查特定错误string{return fmt.Sprintf错误%d:%s,e.Code,e.Message}//创建自定义错误err3:=MyError{Code:404,Message:if errors.Iserr,fs.ErrNotExist{fmt.Println配置文件不存在,将使用默认配置}}资源不存在,}并发编程基础goroutinegoroutine是Go的轻量级线程,由Go运行时管理,比传统线程更高效//启动goroutinefunc sayHello{fmt.Println你好,世界!}//使用go关键字启动goroutinego sayHello//函数在新的goroutine中执行,不阻塞当前程序//匿名函数的goroutinego func{fmt.Println在goroutine中执行的匿名函数}//带参数的goroutinegofuncname string{fmt.Printf你好,%s!\n,name}张三goroutine非常轻量,创建成千上万个goroutine是很常见的Go运行时会自动在多个操作系统线程上多路复用这些goroutine基础channelchannel是goroutine间通信和同步的主要方式//创建通道ch:=makechan int//无缓冲通道ch2:=makechan int,10//缓冲通道,容量为10//发送数据到通道ch-42//将42发送到通道//从通道接收数据value:=-ch//从通道接收数据并赋值给value//关闭通道closech//关闭通道,不能再发送数据缓冲通道缓冲通道有一个容量,发送操作在缓冲区满时阻塞,接收操作在缓冲区空时阻塞//缓冲通道示例ch:=makechan int,3//容量为3的缓冲通道//发送数据(不会阻塞,因为有足够缓冲空间)ch-1ch-2ch-3//再发送会阻塞,因为缓冲区已满//ch-4//此操作会阻塞//接收一个值,腾出缓冲空间-ch//接收1//现在可以再发送了ch-4无缓冲通道无缓冲通道的发送和接收是同步的,发送方会阻塞直到有接收方接收数据//无缓冲通道示例ch:=makechan stringgo func{fmt.Println开始发送数据ch-hello//阻塞,直到主goroutine接收数据fmt.Println数据已发送}time.Sleeptime.Second//等待一秒fmt.Println准备接收数据msg:=-ch//接收数据,goroutine得以继续fmt.Println收到:,msg并发模式与竞态条件常见并发模式生产者消费者模式
1.-func producerchchan-int{for i:=0;i10;i++{ch-i//发送数据time.Sleep100*time.Millisecond}closech//生产完毕,关闭通道}func consumeridint,ch-chan int{for value:=range ch{fmt.Printf消费者#%d接收:%d\n,id,value}fmt.Printf消费者#%d退出\n,id}//使用模式ch:=makechanint,5go producerch//启动一个生产者go consumer1,ch//启动一个消费者go consumer2,ch//启动另一个消费者扇出扇入模式竞态条件
2.-竞态条件是指程序的行为依赖于多个操作的执行顺序,而这个顺序是不确定的func generatornums...int-chan int{out:=makechan intgo func{for_,n:=range nums{out-n}closeout}return out}func squarein-chan int-chan int{out:=//竞态条件示例func racyCounter{counter:=0//启动100个goroutine,每个递增计数器100次for i:=0;i100;i++makechan intgo func{for n:=range in{out-n*n}closeout}return{go func{for j:=0;j100;j++{counter++//竞态条件}}}out}func mergecs...-chan int-chan int{out:=makechan intvar wgsync.WaitGroup//为每个输入通道启动一个time.Sleeptime.Second fmt.Println计数器:,counter//可能不是10000}goroutine output:=funcc-chan int{for n:=range c{out-n}wg.Done}wg.Addlencs for_,c:=range cs{go outputc}//等待所有输入通道处理完毕后关闭输出通道gofunc{wg.Wait closeout}return out}使用互斥锁解决竞态条件Mutex包管理与模块化模块简介GoGo模块是Go语言的依赖管理系统,从Go
1.11开始引入,并在Go
1.13成为默认的依赖管理方式模块解决了依赖版本控制和包导入路径问题主要概念模块Module一组相关包的集合,带有版本信息go.mod文件定义模块路径、Go版本和依赖要求go.sum文件包含依赖的加密校验和,确保一致性创建新模块//初始化新模块go modinit github.com/myuser/myproject//生成的go.mod文件内容module github.com/myuser/myprojectgo
1.18添加依赖//添加依赖的两种方式://
1.直接在代码中导入,然后运行import github.com/gin-gonic/gin//然后运行:go modtidy//
2.使用命令显式添加go getgithub.com/gin-gonic/gin//指定版本go getgithub.com/gin-gonic/gin@v
1.
7.4//更新到最新版本go get-u github.com/gin-gonic/gin标准库常用包介绍包包包fmt os/io time格式化输入输出包,提供打印和解析功能操作系统和输入输出功能时间和日期处理功能importfmt//打印函数fmt.Print无换行fmt.Println自动换行fmt.Printf importos ioio/ioutil//Go
1.16前的用法os/exec//import time//获取当前时间now:=time.Nowfmt.Printlnnow//创建特定时间格式化:%d,%s\n,10,字符串//字符串格式化s:=fmt.Sprintf%s有%d个苹果,文件操作file,err:=os.Open文件.txtif err!=nil{//处理错误}defer t:=time.Date2023,time.January,15,14,30,0,0,time.Local//格式化时间张三,5//扫描用户输入var namestringvar ageintfmt.Scanlnname,file.Close//读取文件data,err:=os.ReadFile文件.txt//Go
1.16+//写fmt.Printlnnow.Format2006-01-0215:04:05//解析时间字符串t,err:=agefmt.Scanf%s%d,name,age入文件err=os.WriteFile新文件.txt,[]byte内容,0644//Go
1.16+//time.Parse2006-01-02,2023-01-15//时间操作future:=now.Add24*执行命令cmd:=exec.Commandls,-laoutput,err:=cmd.CombinedOutput time.Hour//明天past:=now.AddDate0,-1,0//上个月//定时器和延时time.Sleep2*time.Second//暂停2秒timer:=time.NewTimer1*time.Second-timer.C//等待定时器触发包包包net/http strings/strconv encoding/jsonHTTP客户端和服务器功能字符串操作和转换功能JSON数据编解码import net/http//简单HTTP服务器http.HandleFunc/,funcw http.ResponseWriter,r importstrings strconv//字符串操作s:=Hello,World!contains:=*http.Request{fmt.Fprintfw,你好,世界!}http.ListenAndServe:8080,strings.Containss,World//truehasPrefix:=strings.HasPrefixs,Hello//nil//HTTP请求resp,err:=http.Gethttps://example.comif err!=nil{//处trueupper:=strings.ToUppers//HELLO,WORLD!replaced:=strings.Replaces,理错误}defer resp.Body.Closebody,err:=io.ReadAllresp.Body//POST请求resp,World,Go,1//Hello,Go!//分割和连接parts:=strings.Splita,b,c,,err:=http.Posthttps://example.com,application/json,//[a,b,c]joined:=strings.Join[]string{a,b,c},-//a-b-strings.NewReader`{name:张三}`//自定义HTTP客户端client:=c//字符串转换i,err:=strconv.Atoi123//字符串到整数s=strconv.Itoa123http.Client{Timeout:10*time.Second,}resp,err:=//整数到字符串f,err:=strconv.ParseFloat
3.14,64//字符串到浮点数b,err:=client.Gethttps://example.com strconv.ParseBooltrue//字符串到布尔值测试与调试单元测试Go内置了单元测试框架,使用testing包,文件名以_test.go结尾//calc.gopackage calcfuncAdda,b intint{return a+b}//calc_test.gopackage calcimporttestingfunc TestAddt*testing.T{//测试用例tests:=[]struct{a,b,want int}{{1,2,3},{0,0,0},{-1,1,0},{5,-2,3},}//运行所有测试用例for_,tt:=range tests{got:=Addtt.a,tt.b ifgot!=tt.want{t.ErrorfAdd%d,%d=%d;want%d,tt.a,tt.b,got,tt.want}}}运行测试基准测试go test//测试当前包go test-v//详细输出go test./...//测试当前目录及子目录所有包go基准测试用于测量函数的性能,函数名以Benchmark开头test-run TestAdd//只运行特定测试func BenchmarkAddb*testing.B{//b.N由测试框架确定,会自动调整以获得准确结果for i:=0;ib.N;i++{Add10,20}}//运行基准测试//go test-bench=.-benchmem表格驱动测试表格驱动测试是Go中常用的测试模式,允许轻松添加测试用例实战示例简单服务器Web使用标准库创建服务器HTTPGo语言的标准库提供了强大的HTTP服务器功能,无需依赖第三方框架即可快速搭建Web服务//main.gopackage mainimportfmt lognet/httpfunc helloHandlerwhttp.ResponseWriter,r*http.Request{fmt.Fprintfw,你好,世界!\n fmt.Fprintfw,请求路径:%s\n,r.URL.Path fmt.Fprintfw,请求方法:%s\n,r.Method}func formHandlerwhttp.ResponseWriter,r*http.Request{//解析表单数据if err:=r.ParseForm;err!=nil{fmt.Fprintfw,解析表单失败:%v,err return}fmt.Fprintfw,表单提交成功!\n//获取表单值name:=r.FormValuename age:=r.FormValueage//响应表单数据fmt.Fprintfw,姓名:%s\n,namefmt.Fprintfw,年龄:%s\n,age}func main{//注册处理函数http.HandleFunc/hello,helloHandlerhttp.HandleFunc/form,formHandler//提供静态文件服务fs:=http.FileServerhttp.Dir./statichttp.Handle/static/,http.StripPrefix/static/,fs//启动服务器fmt.Println服务器启动,监听端口
8080...if err:=http.ListenAndServe:8080,nil;err!=nil{log.Fatal服务器启动失败:,err}}实现REST API使用标准库实现一个简单的REST API,支持JSON数据交换//添加到main.gopackage mainimportencoding/json fmt io lognet/http sync//用户结构体type Userstruct{ID int`json:id`Name string`json:name`Age int`json:age`}//内存存储varusers=[]User{{ID:1,Name:张三,Age:25},{ID:2,Name:李四,Age:30},}mu sync.Mutex nextID=3//获取所有用户func getUserswhttp.ResponseWriter,r*http.Request{w.Header.SetContent-Type,application/jsonmu.Lock defermu.Unlock json.NewEncoderw.Encodeusers}//创建新用户func createUserwhttp.ResponseWriter,r*http.Request{//只接受POST请求if r.Method!=POST{http.Errorw,只支持POST方法,http.StatusMethodNotAllowed return}//读取请求体body,err:=io.ReadAllr.Body iferr!=nil{http.Errorw,读取请求失败,http.StatusBadRequest return}//解析JSON varuser Useriferr:=json.Unmarshalbody,user;err!=nil{http.Errorw,JSON解析失败,http.StatusBadRequest return}//添加新用户mu.Lock user.ID=nextID nextID++users=appendusers,user mu.Unlock//返回新创建的用户w.Header.SetContent-Type,application/json w.WriteHeaderhttp.StatusCreatedjson.NewEncoderw.Encodeuser}func main{//...之前的代码//添加API路由http.HandleFunc/api/users,funcwhttp.ResponseWriter,r*http.Request{switch r.Method{case GET:getUsersw,r casePOST:createUserw,r default:http.Errorw,方法不支持,http.StatusMethodNotAllowed}}//...启动服务器}实战示例并发爬虫基本爬虫架构使用Go的并发特性可以轻松构建高效的网页爬虫以下是一个基本的并发网页爬虫实现//crawler.gopackage mainimportfmtionet/http ospath/filepath stringssync timegolang.org/x/net/html//提取页面中的链接func extractLinksbodyio.Reader[]string{links:=make[]string,0tokenizer:=html.NewTokenizerbody for{tokenType:=tokenizer.Next//达到文档末尾iftokenType==html.ErrorToken{break}//找到开始标签if tokenType==html.StartTagToken{token:=tokenizer.Token//检查是否为链接标签if token.Data==a{for_,attr:=range token.Attr{if attr.Key==href{links=appendlinks,attr.Valbreak}}}}}return links}//下载页面func downloadPageurlstringstring,error{//设置超时的HTTP客户端client:=http.Client{Timeout:10*time.Second,}resp,err:=client.Geturl iferr!=nil{return,fmt.Errorf下载页面失败:%w,err}deferresp.Body.Close//读取响应body,err:=io.ReadAllresp.Body iferr!=nil{return,fmt.Errorf读取内容失败:%w,err}return stringbody,nil}并发下载管理//实现并发爬虫func main{startURL:=https://example.com maxDepth:=2concurrency:=5outputDir:=pages//创建输出目录iferr:=os.MkdirAlloutputDir,0755;err!=nil{fmt.Printf创建目录失败:%v\n,errreturn}//已访问的URL集合visited:=makemap[string]bool varvisitedMu sync.Mutex//创建工作队列queue:=makechan string,100var wgsync.WaitGroup//添加初始URL queue-startURL visited[startURL]=true//启动工作协程for i:=0;iconcurrency;i++{wg.Add1go funcworkerIDint{defer wg.Donefor url:=range queue{fmt.Printf工作器#%d下载:%s\n,workerID,url//下载页面content,err:=downloadPageurl iferr!=nil{fmt.Printf错误:%v\n,err continue}//保存页面内容filename:=filepath.JoinoutputDir,strings.Replaceurl,/,_,-1iferr:=os.WriteFilefilename,[]bytecontent,0644;err!=nil{fmt.Printf保存文件失败:%v\n,err}//提取链接并加入队列links:=extractLinksstrings.NewReadercontent for_,link:=range links{//处理相对URL if!strings.HasPrefixlink,http{//简化处理,实际需要更完善的URL拼接link=https://example.com+link}//检查是否已访问visitedMu.Lock if!visited[link]{visited[link]=true//控制爬取深度if lenvisitedmaxDepth*100{queue-link}}visitedMu.Unlock}}}i}//等待一段时间或直到达到特定条件time.Sleep30*time.Second//关闭队列并等待所有工作完成closequeue wg.Wait fmt.Printf爬取完成!共访问%d个URL\n,lenvisited}性能优化与最佳实践内存管理与垃圾回收Go语言使用自动垃圾回收,但开发者应了解其工作原理和优化技巧减少内存分配频繁的内存分配会增加垃圾回收压力可以通过以下方式减少分配•复用对象而非每次创建新对象预分配切片容量make[]int,0,capacity使用对象池sync.Pool//使用对象池示例var bufferPool=sync.Pool{New:func interface{}{return newbytes.Buffer},}//获取缓冲区buffer:=bufferPool.Get.*bytes.Bufferbuffer.Reset//使用缓冲区...//归还缓冲区bufferPool.Putbuffer避免内存泄漏虽然有垃圾回收,但某些情况仍可能导致内存泄漏•goroutine泄漏未终止的goroutine会占用资源•大型切片的子切片引用了大数组的小切片•未关闭的资源文件、网络连接等//避免切片泄漏示例//问题代码func getSubsetdata[]int[]int{return data[:10]//返回的切片仍引用原数组}//修复方法func getSubsetFixeddata[]int[]int{result:=make[]int,10copyresult,data[:10]return result//返回新分配的切片}代码规范与风格Go社区有着严格的代码规范,遵循这些规范可以提高代码质量和可维护性命名约定•使用驼峰命名法(CamelCase)学习资源与社区官方文档与教程官方网站golang.org提供全面的文档、教程和标准库参考Go Tourtour.golang.org交互式学习平台Go Blogblog.golang.org官方博客,探讨Go最佳实践Go Playgroundplay.golang.org在线编写和分享Go代码标准库文档pkg.go.dev详细的API文档社区资源推荐书籍讨论社区书名作者适合读者•Go Forumforum.golangbridge.org《Go语言圣经》Alan A.A.Donovan,Brian W.Kernighan初学者到中级•Reddit:r/golang•Stack Overflow:Go标签《Go语言实战》William Kennedy等有编程基础的初学者•Gophers Slack社区《Go程序设计语言》Alan A.A.Donovan,Brian W.Kernighan所有级别•Go语言中文网studygolang.com•Golang中国golangtc.com《Go Web编程》Sau SheongChang Web开发者《深入解析Go》Randall Morris等高级开发者开源项目学习《Go并发编程实战》Katherine Cox-Buday中级到高级•Docker:容器平台•Kubernetes:容器编排系统在线课程•Gin:Web框架•Hugo:静态网站生成器•Coursera:Programming with Google Go(University ofCalifornia)•Prometheus:监控系统•Udemy:Go:The CompleteDevelopers Guide•etcd:分布式键值存储•edX:Web DevelopmentwithGo•CockroachDB:分布式SQL数据库•极客时间:Go语言核心36讲•掘金小册:Go语言上手指南博客与新闻•Go Weekly:每周通讯•Golang Newsgolangnews.com•Go Time:Golang播客•Dave Cheney博客•Go夜读talkgo.org•微信公众号:Golang中国常用工具与框架类别推荐框架/库Web框架Gin,Echo,Beego,Iris,Fiber课程总结与展望语言核心优势回顾Go未来发展趋势泛型支持完善Go
1.18引入的泛型特性将持续优化,提供更灵活的类型系统云原生领域持续增长作为云基础设施领域的主导语言,Go将继续在云原生生态系统中扩展WebAssembly支持增强随着WASM标准的发展,Go对WebAssembly的支持将更加完善AI和数据科学应用虽然Python在这些领域占主导,但Go正逐步进入高性能AI系统和数据处理领域改进的开发工具IDE支持、调试工具和性能分析工具将变得更加强大更好的错误处理预计未来版本会引入改进的错误处理机制进阶学习路径1深入底层原理学习Go的内部实现机制,包括•GC实现原理与优化•goroutine调度器工作原理•内存分配与管理机制•编译器与工具链实现2专业领域应用根据兴趣和职业发展方向,专注于特定领域•微服务架构与服务网格•区块链技术开发•系统编程与DevOps工具•高性能数据处理系统高性能3贡献开源项目Go语言的编译速度和运行效率接近低级语言,垃圾回收机制经过多次优化,能够满足高性能应用的需求强大的并发模型使其特别适合多核处理器环境参与Go社区开源项目,提升实战经验•为流行项目贡献代码简洁设计•创建并维护自己的开源库•参与代码审查和社区讨论语法简洁明了,避免了许多现代编程语言的复杂特性学习曲线平缓,新开发者能够快速掌握代码风格统一,提高了团队协作效率和代码可维护性•分享经验和教程原生并发。
个人认证
优秀文档
获得点赞 0