文章目录
阅读前置条件
- 具备1种后端语言开发经验
- 具备基本网络编程能力与并发思想
- 了解计算机体系架构与Linux基础
golang环境安装
- 版本安装 :https://studygolang.com/dl
基于go1.22.0.windows-amd64.msi (60MB)稳定版本 - gopath配置
Windows版本安装自动配置,或类似JavaHome配置
golang特点
- go优势:
- 简单部署(可以直接编译成机器码、不依赖其他库、直接运行即可部署)
- 静态类型语言(编译的时候检查出来隐藏问题)
- 语言层面并发支持
- 强大的标准库(runtime系统调度机制、高效率的GC、丰富的标准库)
- 简单易学(OOP、C语言基因、跨平台);大厂
- GO应用场景
- 云计算基础设施领域(docker、k8s、etcd、consul)
- 基础后端软件(tidb、influxdb)
- 微服务(go-kit、micro、typhon)
- 互联网基础设施(以太坊、hyperledger)
- 缺点:
- 包管理,大部分在GitHub上
- 无泛化类型
- 所有的Exception都用Error来处理
第一个Go程序
Go语言变量声明
package main
/* 四种变量的声明方式 */
import "fmt"
// 声明全局变量只支持下面的方法一、二、三的格式。不支持:=方式来声明
var A = 100
func main(){
// 方法一:声明变量a
var a int
fmt.Println("a = ", a)
fmt.Printf("type of a is %T \n", a )
// 下面的写法是错误的:invalid operation: "a = " + a (mismatched types untyped string and int)
// fmt.Println("a = "+a)
// 方法二:
var b int = 100
fmt.Println("b = ", b)
fmt.Printf("type of b is %T \n", b )
var bb string = "abcd"
fmt.Printf("bb = %s , type of bb is %T \n",bb , bb )
// 方法三:
var c = 100
fmt.Println("c = ", c)
fmt.Printf("type of c is %T \n", c )
var cc = "decg"
fmt.Printf("cc = %s , type of cc is %T \n",cc , cc )
// 方法四:(常用方法,省略var关键字、自动匹配)
e := 100
// 这里如果使用string格式化输出会报错
// fmt.Printf("e = %s , type of e is %T \n",e , e )
fmt.Printf("e = %d , type of e is %T \n",e , e )
pi := 3.14
fmt.Printf("pi = %f , type of pi is %T \n",pi , pi )
fmt.Printf(" A = %s , type of A is %T \n",A , A )
// 声明多个变量
var xx,yy int = 100,200
fmt.Println(" xx =",xx," yy = ",yy)
var kk, ll = 100,"Huathy"
fmt.Println("kk = ",kk," ll = ",ll)
var(
vv int = 100
jj bool = true
)
fmt.Println("vv = ",vv ," jj = ",jj)
}
常量
对于常量的修改在运行时会报错
package main
import( "fmt")
const (
// iota:自增关键字,初始为0 * 步长为2
ZHEJIANG = iota * 2 // 0
GUANGDONG // 1
)
// 注意:iota只能配合const()进行使用
const( // iota从第一行为0开始,逐行+1
a,b = iota+1,iota+2 // iota=0,a=1,b=2
c,d // iota=1,c=2,d=3
e,f = iota*2,iota*3 // iota=2,e=4,f=6
g,h // iota=3,g=6,h=9
)
// const prov(
// ZHEJIANG = 1
// GUANGDONG = 2
// )
func main(){
const a1 = 1;
fmt.Println("a = ", a1)
fmt.Println("ZHEJIANG = ", ZHEJIANG)
fmt.Println("GUANGDONG = ", GUANGDONG)
// a = 222
fmt.Println(a,b,c,d,e,f,g,h)
}
Golang多返回值的三种写法
package main
import ("fmt")
func fool(a string ,b int) int{
fmt.Println("a = ",a)
fmt.Println("b = ",b)
c := 100
return c
}
// 匿名返回值
func fool2(a string ,b int) (int,int){
fmt.Println("a = ",a)
fmt.Println("b = ",b)
return 666,777
}
// 有形参名返回值
func fool3() (r1 int,r2 int){
r1,r2 = 10000,20000
return
}
func fool4() (r1,r2 int){
r1,r2 = 10000,20000
return
}
func main(){
c := fool("asdf",1000)
fmt.Println(c)
a,b := fool2("asdf",1000)
fmt.Println(a," - ",b)
a,b = fool3()
fmt.Println(a," - ",b)
a,b = fool4()
fmt.Println(a," - ",b)
}
go函数
注意:这里的lib需要放到go环境目录下的src下
package main
import (
"go_study/lib1"
"go_study/lib2"
)
func main(){
lib1.Lib1Test()
lib2.Lib2Test()
}
import匿名与别名导包方式
package main
// lib1,lib2需要放到gopath下的src目录下
import (
// 以别名的方式导入
mylib "go_study/lib1"
// 导入不使用会报错,但加上_,匿名导入可不使用
_ "go_study/lib2"
)
func main(){
mylib.Lib1Test()
// lib2.Lib2Test()
}
package main
// lib1,lib2需要放到gopath下的src目录下
import (
// 导入全部方法,可直接写方法名使用导入的方法。但不建议!
. "go_study/lib1"
// 导入不使用会报错,但加上_,匿名导入可不使用
_ "go_study/lib2"
)
func main(){
Lib1Test()
// lib2.Lib2Test()
}
指针
指针:一级指针、二级指针
类比:Java的引用传递(实参)和值传递(形参)
package main
import "fmt"
func changeVal(p int){
p = 10
}
// 指针传递
func changeVal2(p *int){
*p = 10
}
func swap(a *int,b *int){
var temp = *a;
*a = *b;
*b = temp;
}
func main(){
var a int = 1
changeVal(a)
fmt.Println(a) //输出 1
changeVal2(&a)
// fmt.Println(a) //输出 cannot use &a (value of type *int) as int value in argument to changeVal
fmt.Println(a) //输出 10
var aa,b = 10,20;
swap(&aa,&b)
fmt.Println(aa,b) // 20 10
}
defer关键字结束(defer会在结束时调用,类似Java的finally)
package main
import "fmt"
func deferFunc() int {
defer fmt.Println("defer func end ... ")
fmt.Println("defer func call ... ")
return 0
}
func returnFunc() int {
defer fmt.Println("return func end ... ")
fmt.Println("return func call ... ")
return 2
}
func returnAndDefer() int {
defer deferFunc()
return returnFunc()
}
func main() {
// 类似Java关键字finaly
defer fmt.Println("main end")
defer fmt.Println("main22 end")
fmt.Println("main hello go 1")
var a = returnAndDefer()
fmt.Println(a)
/** 输出
main hello go 1
return func call ...
return func end ...
defer func call ...
defer func end ...
2
main22 end
main end
*/
}
slice切片
数组与动态数组的定义
package main
import "fmt"
func prtArr(ar []int){
// 引用传递
for _,val := range ar{
fmt.Print(val,",")
}
fmt.Println()
ar[0]=100
}
func main(){
var arr [10] int
for i := 0; i < 10; i++ {
fmt.Print(arr[i]," ")
}
fmt.Println()
arr2 := [5]int{1,2,3,4}
for idx,val := range arr2{
fmt.Println("i=",idx,"val=",val)
}
fmt.Printf("arr types = %T \n",arr) // [10]int
fmt.Printf("arr2 types = %T \n",arr2) // [5]int
arr3 := []int{1,2,3,4}
fmt.Printf(" arr2 types = %T \n",arr3) // []int
prtArr(arr3)
for _,val := range arr3{
fmt.Print(val,",")
}
}
动态数组与切片的四种声明方式
package main
import "fmt"
// slice切片的四种声明方式
func main(){
// 声明方式1
slice1 := []int{1,2,3}
fmt.Printf("len = %d, slice= %v \n",len(slice1),slice1)
// 声明方式2
var slice2 []int
fmt.Printf("len2 = %d, slice2= %v \n",len(slice2),slice2)
// 由于没有开辟内存空间,这时候访问索引会报错
// 开辟内存空间
slice2 = make([]int, 3)
fmt.Printf("len2 = %d, slice2= %v \n",len(slice2),slice2)
// 方式三
// var slice3 []int = make([]int, 3)
// 方式四
slice3 := make([]int, 3)
fmt.Printf("len3 = %d, slice3= %v \n",len(slice3),slice3)
// 判断一个slice是否为空
fmt.Println((slice1 == nil))
}
slice切片追加长度与截取
package main
import "fmt"
func main(){
// 长度为3,容量(自增步长)为5,默认情况下cap步长与数组长度相同
var nums = make([]int,2,3)
// cap求数组容量
fmt.Printf("len=%d , cap = %d , slice = %v \n",len(nums),cap(nums),nums)
nums = append(nums,1)
fmt.Printf("len=%d , cap = %d , slice = %v \n",len(nums),cap(nums),nums)
nums = append(nums,1)
fmt.Printf("len=%d , cap = %d , slice = %v \n",len(nums),cap(nums),nums)
// 浅拷贝
s1 := nums[0:2]
nums[0] = 100
// 深拷贝,copy函数
s2 := make([]int,3)
copy(s2,nums)
fmt.Printf("len=%d , cap = %d , slice = %v \n",len(s1),cap(s1),s1)
fmt.Printf("len=%d , cap = %d , slice = %v \n",len(s2),cap(s2),s2)
}
map的声明与使用
map的声明方式
package main
import "fmt"
func main(){
var map1 map[string]string
if(map1 == nil){
fmt.Println(" map1 是一个空map")
}
// 在使用前需要用make为map开辟内存空间
map1 = make(map[string]string , 10)
map1["one"] = "java"
map1["two"] = "python"
map1["three"] = "c"
fmt.Println(map1)
// 声明方式2
map2 := make(map[int]string)
map2[1] = "java"
map2[2] = "python"
map2[3] = "c"
fmt.Println(map2)
// 声明方式3
map3 := map[int]string{
1:"java",
2:"py",
3:"c",
}
fmt.Println(map3)
}
map的使用
package main
import "fmt"
func main(){
// 创建
prov := make(map[string]string)
// 添加
prov["cn"] = "ZJ"
prov["jp"] = "TK"
prov["usa"] = "NK"
// 遍历
for key,val := range prov{
fmt.Print("key=",key," val=",val,"\n")
}
// 删除
delete(prov,"jp")
prov["usa"] = "GG"
fmt.Println("-----------------")
// 遍历
for key,val := range prov{
fmt.Print("key=",key," val=",val,"\n")
}
}
OOP面向对象
struct结构体
package main
import "fmt"
// 声明一种数据类型myint,int的一个别名
type myint int
// 结构体:将多种基本数据类型组合到一起。类比Java的class。
type Book struct{
title string
author string
}
func main(){
var a myint = 10
fmt.Println("a=",a)
fmt.Printf("type of a = %T \n",a)
var book Book
book.title = "JAVA"
book.author = "HUATHY"
fmt.Println("book=",book)
fmt.Printf("type of a = %T \n",book)
}
面向对象的表示与封装
package main
import "fmt"
// 如果类名首字母大写,标识类可以被外部访问
type Hero struct{
// 如果属性名首字母大写,标识非私有属性
Name string
Ad int
Level int
}
func(this Hero)Show(){
fmt.Println("Hero = ", this)
}
func(this Hero)GetName() string{
return this.Name
}
// func(this Hero)SetName(name string){
// // this是调用方法对当前对象的一个拷贝
// this.Name = name
// }
func(this *Hero)SetName(name string){
this.Name = name
}
func main(){
hero := Hero{Name:"Huathy",Ad:1000,Level:10}
hero.Show()
hero.SetName("李四")
hero.Show()
}
面向对象的继承
package main
import "fmt"
type Human struct{
name string
sex string
}
type Man struct{
Human // go的继承:Man继承了Human类的方法
level int
}
func(this Human)Eat(){
fmt.Println("human eat ...")
}
func(this Human)Walk(){
fmt.Println("human walk ...")
}
// Man重写父类方法
func(this *Man)Eat(){
fmt.Println("Man eat ...")
}
// 子类的新方法
func(this *Man)Fly(){
fmt.Println("Man Fly ...")
}
func main(){
h := Human{"xixi","boy"}
h.Eat()
h.Walk()
fmt.Println(h)
s := Man{Human{"xixi","boy"},99}
s.Walk()
s.Eat()
s.Fly()
fmt.Println(s)
}
多态(interface接口)
父类引用指向子类对象
package main
import "fmt"
type IAnimal interface{
Sleep()
GetColor() string
GetType() string
}
type Cat struct{
color string
}
func(this *Cat) Sleep(){
fmt.Println("cat is sleep")
}
func(this *Cat) GetColor() string{
return this.color
}
func(this *Cat) GetType() string{
return "cat"
}
type Dog struct{
color string
}
func(this *Dog) Sleep(){
fmt.Println("Dog is sleep")
}
func(this *Dog) GetColor() string{
return this.color
}
func(this *Dog) GetType() string{
return "Dog"
}
func showAnimal(animal IAnimal){
animal.Sleep()
fmt.Println(animal.GetColor())
fmt.Println(animal.GetType())
}
func main(){
var animal IAnimal
animal = &Cat{"Black"}
showAnimal(animal)
dog := &Dog{"yellow"}
showAnimal(dog)
}
interface{}空接口与类型断言机制
package main
import "fmt"
func myFUnc(arg interface{}){
fmt.Println("myfunc is call ... ")
fmt.Println(arg)
// interface{} 如何区分引用的数据类型是什么?
// go给interface{}提供了断言机制
// 类比:interface{}类比Java的Object类。而断言机制类比拆箱
// 类型判断
val,ok := arg.(string)
fmt.Printf("arg type is %T \n",val)
if ok{
fmt.Println("arg is string type")
}else{
fmt.Println("arg is not string type")
}
}
type Book struct{
name string
}
func main(){
book := Book{"GO"}
myFUnc(book)
myFUnc(100)
myFUnc("abc")
}
反射
内置pair
变量结构包含type和value
package main
import "fmt"
type Reader interface{
ReadBook()
}
type Writer interface{
WriteBook()
}
type Book struct{
}
func(this *Book)ReadBook(){
fmt.Println("read book ... ")
}
func(this *Book)WriteBook(){
fmt.Println("write book ... ")
}
func main(){
a := "123456"
var b interface{}
b = a
// 断言(强转!)
val,_ := b.(string)
fmt.Println(val)
book := &Book{}
var r Reader
r = book
r.ReadBook()
var w Writer
// 强转成writer类型
w = r.(Writer)
w.WriteBook()
}