Golang

1、介绍

简介

​ Go起源于 2007 年,并在 2009 年正式对外发布。Go 是非常年轻的一门语言,它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C++ 等编译型语言的性能与安全性”。
​ Go语言是编程语言设计的又一次尝试,是对类C语言的重大改进(访问底层操作系统),它可以进行网络编程、系统编程、并发编程、分布式编程。不损失应用程序性能的情况下降低代码的复杂性,具有“部署简单、并发性好、语言设计良好、执行性能好”等优势,目前国内诸多 IT 公司均已采用Go语言开发项目
​ Go语言有时候被描述为“C 类似语言”,或者是“21 世纪的C语言”。Go 从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等很多思想,还有C语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配。
​ Go语言没有类和继承的概念,所以它和 Java 或 C++ 看起来并不相同。但是它通过接口(interface)的概念来实现多态性。Go语言有一个清晰易懂的轻量级类型系统,在类型之间也没有层级之说。因此可以说Go语言是一门混合型的语言。
​ 此外,很多重要的开源项目都是使用Go语言开发的,其中包括 Docker、Go-Ethereum、Thrraform 和 Kubernetes。

教学

特点

  • 简洁、快速、安全
  • 并行、有趣、开源
  • 内存管理、数组安全、编译迅速

2、语法

基础格式

package main //包名import "fmt" //导包func main() { //主方法入口fmt.Printf("hello, world\n")
}

导包

import "fmt" //单个导包
import ( //多个导包"fmt""math/rand"
)
//ps:调用时只需要通过 包名.方法 即可,方法首字母是大写 如math.Pi

变量类型

//基本类型
bool   //布尔型
string //字符串
int  int8  int16  int32  int64          //有符号整数型 ps:int8 占8位的整数型
uint uint8 uint16 uint32 uint64 uintptr //无符号整数
byte   //uint8 的别名
rune   //int32 的别名,代表一个Unicode码
float32 float64      //浮点类型,存在精度丢失问题
complex64 complex128 //复数 ps:complex64表示双32位浮点数(实数部分和虚数部分)//补充
float32 //单精度浮点数,包括:1 个符号位,8 个指数位(小数位),23 个尾数位
float64 //双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
var f2 float32 = 3.14e2 //3.14e2=3.14*10^2,3.14e-2=3.14/10^2//数组类型
[X]类型名 //数组//指针(指向(存储)一个值的内存地址)
//通过指针获取内存地址存储的值  *变量
//获取该值的内存地址  &指针变量
*int //整数型指针,可以存整数型的变量内存地址//Map型
map //键值对类型

变量定义

// 初始值
// 数值类型为 0
// 布尔类型为 false
// 字符串为 ""(空字符串)
// 指针为 nil//参数定义规范
var 参数名 类型
var i int //定义一个
var c, python, java bool //定义一组
var i, j int = 1, 2 //定义一组,赋初始值
k := 3 //简化定义替代var定义,自动判断类型,不能在函数体外使用//常量定义
const World = "世界"  //定义后就不能被修改,不能使用 :=//定义数组
var a [2]string //定义一个长度为2的空值数组,a[0],a[1]
var a [...]string{"a","b"} //赋值的数组,...表示长度为元素的数量
var a [...]string{1:"a",2:"b"} //下标赋值//定义slice(切片)
var arr []int //定义空值切片,空切片值==nil
p := []int{2, 3, 5, 7, 11, 13} //定义长度、容量为6赋值的切片
a := make([]int, 5)   //定义长度和容量为5不赋值的切片
b := make([]int, 5,7) //定义长度为5和容量为7不赋值的切片//指针定义
var ip *int //定义一个空的整数型指针,可以存整数型的变量内存地址 不能使用 :=//定义自定义类型
type MyFloat float64 //给类型其别名//定义结构体(类似于java的实体类,但是没用set、get和有参方法)
type Vertex struct {X, Y int
}//map定义
var m map[string]int = make(map[string]int)//定义空map,map[key类型]value类型
var m = make(map[string]int)//定义空map,map是空的值为nil
m1 := make(map[string]int)//定义空map
var m = map[string]int{"a":1,"b":2} //定义赋值
m := map[string]int{"a":1,"b":2} //定义赋值//定义变量函数
hypot := func(x,y int) int {return (x+y)}

函数

//函数规范
func 函数名(变量名 类型, ...) 返回类型 { 代码...return 返回值
}//自定义函数
func add(x int, y int) int { return x + y
}//自定义函数(简化参数格式)
func add(x , y int) int {  //简化方法也可作用到返回值return x + y
}//多返回值函数
func swap(x, y string) (string, string) {return y, x
}
func main() {a, b := swap("hello", "world") //接受返回值fmt.Println(a, b)
}//返回值起名
func split(sum int) (x, y int) {y = sum - x return//起名后就会赋予初始化值,如int初始值是0,返回时不写就会直接返回值名
}//可变参数函数
func sum(x...int) int {return (x[0]+x[1])
}//匿名函数
hypot := func(x...int) int {return (x[0]+x[1])
}//闭包函数
func add() func()int{i := 0return func()int {i+=1return i}
}//方法接收者函数
func (v *Vertex) Abs() float64 {  //func 和 方法名 之间的参数就是方法接收者return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

接口

//定义接口
type User interface{ //创建接口name(s string) string //接口方法//... 方法
}

循环

//常规for循环
for i := 0; i < 10; i++ { /*代码块*/ }//for条件循环
for sum < 1000 { /*代码块*/ }//for死循环
for {}//for迭代循环1
for i, v := range pow { /*代码块*/ }//for迭代循环2,_忽略key
for _, value := range pow { /*代码块*/ }

判断

//if
if x < 0 {/*代码块*/}
//if..else
if v < lim {/*代码块*/} else {/*代码块*/}//if头添加变量,变量作用域只能在if体里
func add(x int)int{if v := x+1;v > 10{ //定义一个if专属变量vreturn v}return x
}
func main() {fmt.Println(add(10))
}//switch  不带条件就是true
func main() {fmt.Print("Go runs on ")switch os := runtime.GOOS; os {case "darwin":fmt.Println("OS X.")case "linux":fmt.Println("Linux.")default:fmt.Printf("%s.", os)}
}

错误/错误捕获

//抛出错误的三种方法
func (e *自定义类型) Error() string { //实现Error方法//代码块
}
自定义类型(x).Error() //调用errors.New("参数为空") //通过errors.New返回,返回值类型是errorpanic("出错了") //通过panic抛出错误defer func() { //函数结束前执行匿名函数(延迟执行)if err:=recover();err != nil { //捕获错误fmt.Println("======捕获到错误=====")fmt.Println("异常名称:",err)}
}()//这个()是调用defer的匿名函数func()

3、说明

类型转换

//类型转换
var i int = 42
var f float64 = float64(i)
a := 42
b := float64(a)

切片

/*len长度:元素个数cap容量:要拷贝的数组/切片的长度-开头数
*/
var arr []int{0,1,2,3,4,5} //定义切片 len=6 cap=6
a:= arr[1:4]  //定义切片 len=3 cap(arr的len-开头数)=5
p[1:4] //获取值,包头不包尾,结果1 2 3
p[:3]  //获取值,不写头从0开始,包头不包尾,结果0 1 2
p[4:]  //获取值,不写尾从指定头开始获取全部,包头不包尾,结果4 5/*添加时如果:切片cap<新元素个数+旧元素个数,会生成一个新的切片len=新元素个数+旧元素个数cap=新的len+旧元素个数
*/
arr = append(arr, 1,2,...)  //添加元素到切片/*for 循环的 range 格式可以对 slice 或者 map 进行迭代循环
*/
for i, v := range pow {fmt.Printf("2**%d = %d\n", i, v)
}

结构体

type Vertex struct {X, Y int
}
v1 = Vertex{1, 2}  //顺序赋值,按顺序赋值,结果1,2
v3 = Vertex{1}  //顺序赋值,Y被省略,结果1,0
v2 = Vertex{Y: 1}  //指定赋值,X被省略,结果0,1
v4 = &Vertex{1, 2} //类型为 *Vertex

延迟执行

//defer 等待上层函数执行完毕后才执行,等待时不会堵塞其它函数/命令
//简单点说就是,不管在那使用defer都只会在函数结束前其它函数后去执行defer的函数
func main() {fmt.Println("hello1") //第1输出defer fmt.Println("world") //第4输出fmt.Println("hello2") //第2输出time.Sleep(time.Duration(2)*time.Second)fmt.Println("hello3") //第3输出
}//补充,当有多个同级defer时,会把defer进行压栈(后进先出)
func main() {fmt.Println("counting")for i := 0; i < 10; i++ {defer fmt.Println(i)}defer add(1)fmt.Println("done")
}func add(a int){fmt.Println(a,"start")
}

Map

m := make(map[string]int)
m[key] = elem   //插入或修改一个元素
elem := m[key]  //获取元素value值
elem,ok := m[key] //获取元素value值 判断是否存在,不存在获取的是 elem=0 ok=false
delete(m, key)  //删除元素

闭包

//闭包特点就是常驻内存(声明后就一直在内存直到程序关闭),互不干扰
//闭包构建一个函数里返回另一个函数
func main() {var fn = add()fmt.Println(fn(),fn(),fn(),)
}// func 函数名() 返回值[函数]{func 函数名() {返回值}}
func add() func()int{i := 0return func()int {i+=1return i}
}

方法

//方法接收者接受的参数可以是 自定义类型 和 结构体
//作用:可以给方法接受者(自定义类型 和 结构体)添加任意自定义方法
//首字母大写的方法外部引用时可见,反之相反
type ABC int //自定义类型
func (a ABC) Aaa() int{ //ABC是方法接收者,给接收者添加自定义方法,Aaa()方法return int(a)+5
}func main() { v := ABC(10) //初始化自定义方法值为10fmt.Println(v.Aaa()) //调用方法
}

指针

func A(f *float64){*f = *f + 3.14fmt.Println("进入A方法后f:",*f)
}func B(f float64){f = f - 1fmt.Println("进入B方法后f:",f)
}func main() {var f float64 = 3.14fmt.Println("初始值的f:",f)A(&f) //通过指针,是传入f的内存地址,可以对f进行修改B(f) //不通过指针,是拷贝f的副本传入B方法,修改的是副本fmt.Println("现在的f:",f)
}

接口

type User interface{ //创建接口name(s string) string //接口方法
}type MyUser string //自定义类型
func (mu MyUser) name(s string)string{//实现User接口方法return s+"用户"+string(mu)
} func main(){//var u User = MyUser("bb")//实例化接口 方法1 结果:aaa用户bbvar u User = new(MyUser)//实例化接口 方法2 结果:aaa用户fmt.Println(u.name("aaa"))//调用接口方法
}

并行并发

并发:任务在单线程里快速交替执行,肉眼感官上就是同时运行但其实不是
并行:多个线程同时执行多个任务

不并发、不并行:想喝开水,就一直等烧开,喝完水再去做别的事
并发:想喝开水,等水烧开过程跑去做别的事,水开了再喝
并行:想喝开水,叫别人替你烧水,自己去做别的事情

goroutine:goroutine是Go并行设计的核心。goroutine说到底其实就是线程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。goroutine比thread更易用、更高效、更轻便。
goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过go关键字实现了,其实就是一个普通的函数。

//main方法坑:main方法自身不会堵塞,所以再执行go时不让main进行堵塞,main一结束程序也就结束就看不见go执行效果
//下面是个简单的励志
func main() {go Run("A")Run("b")
}func Run(string2 string)  {for i := 0; i < 10; i++ {runtime.Gosched() //让出执行权,进入堵塞等待再次获取执行权fmt.Printf(string2)}
}

goroutine之间如何进行数据的通信呢,Go提供了一个很好的通信机制channel(通道机制)

//通过chan进行堵塞func main() {c := make(chan bool) //数据通信对象,同步的(双方都执行完毕后关闭)//c := make(chan bool 1) //带缓冲的数据通信对象,异步的(存储方数据都存储在缓冲区即可关闭)go Run("A",c)go Run("B",c)go Run("C",c)for i := 0; i < 3; i++ {<- c}
}func Run(s string,c chan bool)  {fmt.Println()for i := 0; i < 10; i++ {fmt.Printf(s)}c <- true
}
//带缓存的作用
func main() {c := make(chan int, 2)//最大存储2个intc <- 1c <- 2fmt.Println(<-c)fmt.Println(<-c)
}//显示关闭用法
func main() {c := make(chan int)go func() {for i := 0; i < 5; i++ {c <- i}close(c) //显示关闭channel}()for v := range c{ //显示关闭后结束循环fmt.Println(v)}
}
package mainimport ("fmt""runtime""sync"
)func main() {wg := sync.WaitGroup{} //创建等待任务wg.Add(3) //添加任务数量runtime.GOMAXPROCS(runtime.NumCPU()) //使用多线程,不设置默认是单线程go Run("A",&wg)go Run("B",&wg)go Run("C",&wg)wg.Wait() //等待任务=0,结束堵塞}func Run(s string,wg *sync.WaitGroup)  {fmt.Println()for i := 0; i < 10; i++ {fmt.Printf(s)}wg.Done() //任务数量-1
}
//多线程接受channel
//select{ case 接受/发送 case}
package main
import "fmt"func fibonacci(c, quit chan int) {x, y := 1, 1for {select {case c <- x: //发送 cx, y = y, x + ycase v,ok :=<-quit: //接受 quit,v是值 ok是chan对象是否被关闭fmt.Println("quit")returncase <- time.After(3 * time.Second): //设置监听超时,在时间内没用接受到channel执行,不能和default一起使用println("timeout")o <- truebreak// default:/*当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)简单来说就是:case都不满足直接运行default不进行等待*/}}
}func main() {c := make(chan int)quit := make(chan int)go func() {for i := 0; i < 10; i++ {fmt.Println(<-c)}quit <- 0}()fibonacci(c, quit)
}

4、使用

反射

//获取方法、函数、字段
package mainimport ("fmt""reflect"
)type Word struct {A intB stringC string
}type dis struct {Wordaut string
}func (t Word) spelling(){}
func (t Word) Reading(s string){}func main() {//info(Word{A: 1,B: "hello",C: "!!!"})//info(info) //ps:获取函数名称和获取类型名称是不一样的info1(dis{Word{A: 1,B: "hello",C: "!!!"},"张三"})
}func info(i interface{}){t:=reflect.TypeOf(i) //获取字段、方法、函数v:=reflect.ValueOf(i) //调用字段、方法、函数fmt.Println("类型名称:",t.Name()) //获取类型名称//fmt.Println("函数名称:",runtime.FuncForPC(v.Pointer()).Name()) //获取函数名称fmt.Println("类型",t.Kind()) //获取类型 如:main.Word 类型就是structfmt.Println("-----------")if t.Kind()!=reflect.Struct {return}for i:=0;i<t.NumField();i++{fd :=t.Field(i)fmt.Println("字段名称:",fd.Name,"字段类型:",fd.Type,"字段值:",v.Field(i).Interface())}fmt.Println("-----------")for i:=0;i<t.NumMethod();i++{ //获取不到私有方法(首字母小写方法)fd :=t.Method(i)fmt.Println("方法名称:",fd.Name,"方法类型:",fd.Type)}//t.FieldByIndex([]int{0,0})}
func info1(i interface{}){t:=reflect.TypeOf(i) //获取字段、方法、函数v:=reflect.ValueOf(i) //获取值用for i:=0;i<t.NumField();i++{sub :=v.Field(i).Kind()if sub == reflect.Struct{for x:=0;x< reflect.TypeOf(v.Field(i).Interface()).NumField();x++{fmt.Println(t.FieldByIndex([]int{i,x})) //打印结构字段}}else {fmt.Println(t.Field(i))}}
}
package mainimport ("fmt""reflect"
)func main() {/*//反射修改基本类型x := 100fmt.Println(x)v:=reflect.ValueOf(&x)  //获取对象指针v.Elem().SetInt(999) //修改值fmt.Println(x)*///反射调用方法u := User{"Jke",12}fmt.Println(u)v := reflect.ValueOf(u) //获取对象m := v.MethodByName("Hello") //获取方法args := []reflect.Value{reflect.ValueOf("Make"),reflect.ValueOf(15)}//要传递的参数b:=m.Call(args) //执行方法fmt.Println(b[0])
}type User struct {name stringage int
}func (u User) Hello(str string,i int) bool{fmt.Println("hello!",str,"[",i,"age]")return true
}

time

time.NewTimer(time.Second*1)//创建一个指定时长的定时器
time.NewTicker(time.Second*1)//创建一个指定时长的打点器
time.Tick(200 * time.Millisecond) //创建一个指定时长的打点器
ticker.Stop() //停止打点/定时器(手动停止)

原子

Add 【增加和减少 线程安全】
CompareAndSwap 【比较并交换 线程安全】
Swap 【交换 线程安全】
Load 【读取 线程不安全】
Store 【存储 线程不安全】
=============================================
Load 只保证读取的不是正在写入的值,Store只保证写入是原子操作
atomic.AddUint32(&addr,n) //Add 增
atomic.AddUint32(*addr,uint32(int32(n))) //Add 减
atomic.AddUint32(&addr,^uint32(-n-1)) //Add 减//替换 addr等于old,addr会被替换成new
ok:=atomic.CompareAndSwapInt32(&addr,old,new)//读取 也就是load,只能保证读取的不是正在写入的值
v:=atomic.LoadInt32(&addr)//存储 也就是Store,只保证写入是原子操作
atomic.StoreInt32(&value,newaddr)
//load和store不保证安全例子
package main
import ("fmt""sync""sync/atomic"
)
var (wg  sync.WaitGroupmu  sync.Mutexnum int32
)
func wrap(callback func()) {wg.Add(1)go func() {callback()wg.Done()}()
}func main() {// 并发不安全 结果值不确定wrap(incNumAtomic)wrap(incNumAtomic)// 1200, 并发安全wrap(incNumAtomic2)wrap(incNumAtomic2)wg.Wait()fmt.Printf("num=%d\n", num)
}
func incNumAtomic() {for i := 0; i < 10000; i++ {// atomic.Load*系列函数只能保证读取的不是正在写入的值(比如只被修改了一半的数据)// 同样的atomic.Store* 只保证写入是原子操作(保证写入操作的完整性)val := atomic.LoadInt32(&num)atomic.StoreInt32(&num, val+1)}
}
func incNumAtomic2() {for i := 0; i < 600; i++ {atomic.AddInt32(&num, 1)}
}

互斥锁

var mutex = &sync.Mutex{} //创建对象
mutex.Lock()   //上锁
mutex.Unlock() //解锁
//&sync.Mutex{} 创建互斥锁,mutex.Lock()上锁,mutex.Unlock()解锁
package main
import ("fmt""sync/atomic""time"
)
func main() {var mutex = &sync.Mutex{}sum := 0sum1 := 0for i := 0; i < 1000; i++ {go func() {mutex.Lock()sum1 += 1mutex.Unlock()}()}for i := 0; i < 1000; i++ {go func() {sum += 1}()}time.Sleep(time.Second*3)fmt.Println(sum,"===",sum1)
}

排序

sort.Strings(x)  //对string切片进行升序排序
sort.Ints(x) //对int切片进行升序排序
sort.IntsAreSorted(ints) //判断int切片是否进行了升序排序,其它同类就是改类型
package main
import ("fmt""sort"
)
type byLength []string//实现sort.Interface的方法 len、Swap、Less就可以进行自定义的排序
func (s byLength) Len() int {//为集合内元素的总数return len(s)
}
func (s byLength) Swap(i, j int) {//替换方式s[i], s[j] = s[j], s[i]
}
func (s byLength) Less(i, j int) bool { //比较方式return len(s[i]) < len(s[j])
}func main() {fruits := []string{"peach", "banana", "kiwis"}sort.Sort(byLength(fruits))fmt.Println(fruits)
}

strings

strings.HasPrefix(s, prefix)//判断字符串s是否以prefix开头
strings.HasSuffix(s, suffix)//判断字符串s是否以suffix结尾strings.Index(s, str)//判断str在s中首次出现的位置,没有返回-1
strings.LastIndex(s , str)//判断str在s中最后出现的位置,没有返回-1strings.Replace(str, old , new, n)//字符串替换, n为替换次数strings.Count(str , substr)//统计substr出现个数
strings.Repeat(str , count)//重复count次str 如a重复5次=aaaaastrings.ToLower(str)//转为小写
strings.ToUpper(str)//转为大写strings.TrimSpace(str)//去掉字符串首尾空白字符
strings.Trim(str, cut)//去掉字符串首尾cut字符
strings.TrimLeft(str, cut)//去掉字符串包含cut的字符
strings.TrimRight(str, cut)//去掉字符串包含cut的字符
strings.TrimSuffix(str, cut)//删除字符串里的cut字符strings.Field(str)//返回空格分隔的所有子串
strings.Split(str, split)//返回split分隔的所有子串strings.Join([]s1, sep)//用sep拼接切面strings.Itoa(i)//把一个整数i转成字符串
strings.Atoi(str)//把一个字符串转成整数

字符串格式化

fmt.Printf("%v\n", p)
/*%v  输出值%+v 输出括结构体时包含字段名%#v 该值的源码片段%T  类型%t  布尔型%d  十进制格式输出%b  二进制格式输出%c  输出给定整数的对应字符%x  输出十六进制编码%f  浮点型输出%e  科学记数法浮点型输出%E  同上%s  基本的字符串输出%q  带双引号的输出%x  使用 base-16 编码的字符串,每个字节使用 2 个字符表示%p  输出指针%xd x是数字,表示占x个位符,右对齐%-6d x是数字,表示占x个位符,左对齐
*/

正则表达式

//查找出匹配正则的语句 或 规定满足正则的语句 pattern:正则语句 str:要匹配的字符串
regexp.MatchStrin(pattern,str) //Match类型 判断字符串是否满足正则语句 返回boolregexp.Compile(pattern)  //创建正则表达式
regexp.MustCompile(pattern) //创建正则表达式 适用于常量regexp.FindString(str) //查找匹配的字符串
regexp.ReplaceAllFunc(str, ide) //用ide替换满足条件的文本

JSON

// JSON 的编码和解码 编码:数据转JSON  解码:JSON转数据
// 编码
func main() {type Stu struct {Name  string `json:"name"` //编码时指定key名Age   intHIgh  bool}stu := Stu{Name: "张三",Age:  18,HIgh: true,}jsonStu, err := json.Marshal(stu) //编码if err != nil {fmt.Println("生成json字符串错误")} //判断是否编码成功
}// 解码
func main() {type StuRead struct {Name  interface{} Age   interface{}HIgh  interface{}}//json字符中的"引号,需用\进行转义,否则编译出错//json字符串沿用上面的结果,但对key进行了大小的修改,并添加了sex数据data:="{\"name\":\"张三\",\"Age\":18,\"high\":true,\"sex\":\"男\",\"CLASS\":{\"naME\":\"1班\",\"GradE\":3}}"str:=[]byte(data) //将字符串转byte(字符转字节码)stu:=StuRead{}err:=json.Unmarshal(str,&stu) //解码,第二个参数必须是指针//解析失败会报错,如json字符串格式不对,缺"号,缺}等。if err!=nil{fmt.Println(err)}
}//对html特殊字符进行转义
buffer := &bytes.Buffer{} //带缓存的byte
encoder := json.NewEncoder(buffer) //创建新的编码
encoder.Encode(t)//编码

XML

type Plant struct {XMLName xml.Name `xml:"config"` //根标签Id      int      `xml:"id,attr"` //根标签属性Age      int     `xml:"age,attr"` //根标签属性Name    string   `xml:"plant2"`  //标签Origin  []string `xml:"chi>origin"`  //标签
}
xml.MarshalIndent(a, " ", "  ") //生成成xml
xml.Unmarshal(data, &v) //解码成对象
package mainimport ("encoding/xml""fmt"
)type Plant struct {XMLName xml.Name `xml:"config"` //根标签Id      int      `xml:"id,attr"` //根标签属性Age        int     `xml:"age,attr"` //根标签属性Name    string   `xml:"plant2"`  //标签Origin  []string `xml:"chi>origin"`  //标签
}type Result struct {XMLName xml.Name `xml:"persons"`Persons []*Plant `xml:"person"`
}func (p Plant) String() string {return fmt.Sprintf("Plant id=%v, name=%v, origin=%v",p.Id, p.Name, p.Origin)
}func main() {coffee := &Plant{Id: 27, Name: "张三"}coffee.Origin = []string{"Ethiopia", "Brazil"}coffee2 := &Plant{Id: 27, Name: "历史"}coffee2.Origin = []string{"Ethiopia", "Brazil"}a := &Result{}a.Persons = []*Plant{coffee,coffee2}out, _ := xml.MarshalIndent(a, " ", "  ") //生成成xmlfmt.Println(xml.Header +string(out))
}//xml.Unmarshal(data, &v) //解码成对象

time

p := fmt.Println
then := time.Now() //当前时间戳
p(then.Year())    //获取当前年
p(then.Month())   //获取当前月
p(then.Day())     //获取当前日
p(then.Hour())    //获取当前小时
p(then.Minute())  //获取当前分
p(then.Second())  //获取当前秒
p(then.Nanosecond() / 1000)//获取当前毫秒
p(then.Nanosecond())//获取当前纳秒
p(then.Location())//获取所在时区time.Unix(now.Unix(), 0)//根据时间戳返回本地时间,秒数和纳秒数p(then.Date())      //获取当前日期
p(then.Weekday())   //获取星期
p(then.Before(now)) //then时间在now时间之前,返回真
p(then.After(now))  //then时间在now时间之后,返回真
p(then.Equal(now))  //then等于now,返回真p(then.Add(diff))   //时间计算t.Format("2006-01-02T15:04:05.999999-07:00") //格式化时间

随机数

rand.Seed(time.Now().UnixNano()) //生成随机数
fmt.Println(rand.Intn(10)) //打印随机数

数字转换

f, _ := strconv.ParseFloat("1.234", 64) //字符串转浮点型,其它类型同理把类型修改即可
i, _ := strconv.ParseInt("123", 0, 64) //字符串转整数型
k, _ := strconv.Atoi("135") //字符串转基础的 10 进制,失败返回错误信息

url

type URL struct {Scheme   stringOpaque   string    // 编码后的不透明数据User     *Userinfo // 用户名和密码信息Host     string    // host或host:portPath     string    // 路径RawQuery string    // 编码后的查询字符串,没有'?'Fragment string    // 引用的片段(文档位置),没有'#'
}url.QueryEscape("/user?id=12") //将字符地址转为安全地址func main() {compelePath := "http://lcoalhost:8080/user/ss?id=1&id2=1&id3=1"f := fmt.PrintlnsP, _ := url.Parse(compelePath) //解析字符串urlcp,_ :=url.ParseRequestURI(compelePath)//解析字符串url,但不包含[#fragment]ap,_ :=url.ParseQuery(compelePath) //解析字符串url,字符串变成map类型f(cp)f(sP)f(ap)f(sP.Host) //返回域名f(sP.Path) //返回子路径 如:域名/user/ss  子路径:/user/ssf(sP.RequestURI()) //返回子路径+参数f(sP.RawQuery) //返回url的参数,如:id=2&id2=3 返回字符串f(sP.Query())  //返回url的参数,返回类型是Map//f(sP.Query().Add) //添加参数 Del删除 Get获取参数f(sP.IsAbs())  //是否为绝对地址args := url.Values{"name": []string{"coco"},"age":  []string{"34"},}f(args.Encode()) //把结构体转url参数compelePath2, _ :=url.Parse("/user/ss?id=1&id2=1&id3=1")fmt.Println(sP.ResolveReference(compelePath2))//通过URI将一个URI补全为对URI
}

os、io、buf、file

filepath.Join("dir1", "dir2", "filename","Q.TXT")//拼接字符串为目录路径
filepath.Dir(p)  //获取文件父级路径
filepath.Base(p) //获取当前选中的文件或者文件夹
filepath.IsAbs("dir1/dir2") //是否是绝对路径
filepath.Split(p) //路径分解为父级路径和当前文件或目录
filepath.Ext(filename) //获取文件后缀
filepath.Rel("a/b/file", "a/b/t/file") //两者之间的相对路径
filepath.Walk(path,func(){}) //遍历路径下全部文件和文件夹,并每次都调用func(){}//————————————————————————————————————————————————————————————————————————————
ioutil.WriteFile("./a.txt",[]byte("AAA"),0666) //字符串写入文件
ioutil.ReadDir("pkg") //获取目录下全部文件
ioutil.ReadAll(os.Open("./a.txt")) //读取文件内容
ioutil.TempDir("DIR", "tmp") //在DIR目录下创建名为tmp的临时目录//————————————————————————————————————————————————————————————————————————————
bufio.NewScanner(os.Stdin) //命令行控制台输入
bufio.NewScanner(os.Stdin).scanner.Scan() //获取控制台输入流状态bufio.NewWriter(os.Create("./c.txt")) //创建新的 Writer 对象
bufio.NewWriter(os.Create("./c.txt")).WriteString("bufferedn") //写入字符串到文件bufio.NewReader(os.Create("./b.txt")) //文件读取到Reader中
bufio.NewReader(os.Create("./c.txt")).Seek(offset, whence) //更改选中光标【参数1:偏移量】【参数2:0从头,1当前,2末尾】//————————————————————————————————————————————————————————————————————————————
os.Remove(path) //删除当前目录下的文件
os.RemoveAll("a") //删除整个目录os.Mkdir("a", 0666) //创建目录
os.Create("./b.txt") //创建文件os.Stat("./a.txt") //获取文件信息
os.Getwd() //获取当前路径
os.Open("./a.txt")//只能用作读取的文件
os.OpenFile("./a.txt", os.O_APPEND, 0666) //以追加模式打开文件os.Setenv("FOO", "1")//设置环境变量
os.Getenv("FOO")//获取环境变量的值
os.Environ()//列出所有环境变量键值对,可以使用strings.SplitN(e, "=", 2)分割获取

命令

//命令行参数
os.Args //获取运行时传入的参数  如:go run dome.go 12 15 [12 15]都是参数下标1开始//命令行标志 go run dome.go -word=opt  [-word]就是标志
flag.String("word", "foo", "a string") //设置标志名为word 默认值foo 描述为a string
flag.Int("numb", 42, "an int")
flag.Bool("fork", false, "a bool")
var svar string
flag.StringVar(&svar, "svar", "bar", "a string var")//指针参数需要在第一个参数传入//子命令标志
barCmd := flag.NewFlagSet("bar", flag.ExitOnError) //设置最高级命令
barLevel := barCmd.Int("level", 0, "level") //给最高命令添加子命令//退出命令
os.Exit(2)//使用os.Exit时defer将不会被执行,用来正常退出程序,0为正常退出码,非零表示错误码(其实没区别)//针对linux系统
//调用命令台命令
dateCmd := exec.Command("java","--help")//调用cmd方法
dateCmd.Output()//返回结果exec.LookPath("ls")//在环境变量中查找可执行二进制文件sigs := make(chan os.Signal, 1) //创建通道
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) //signal接受ctrl+c结束的信号

http

//模拟Get请求
http.Get("http://gobyexample.com") //Get请求
bufio.NewScanner(http.Get("http://gobyexample.com").Body)//把Get请求结果给命令行控制台
scanner.Text() //打印结果//Handle
http.Handle("/hello",Hello{})     //添加对应的处理ServeHTTP,对应web案例
http.HandleFunc("/hello", hello)  //访问指定路径时调用指定方法
http.ListenAndServe(":8090", nil) //绑定端口监听器

5、坑

go语言坑

main

//main方法本身是不堵塞的,在使用goroutine(并发并行)时,不对main进行堵塞时看不见goroutine结果

切片

//切片容器满时添加新元素,底层会重新分配地址,因此原本的切片也就不是同一个
func main(){a:make([]int,0) //原本的切片容器大小0add(a) fmt.Println(a) //想象中是结果[12] 实际是[] 因为内存地址不一样了
}func add(s []int){append(s,12) //容器不够,重新分配了地址并添加旧元素和新元素进去//s :=  append(s,12) //所以建议变量存储并返回
}

大小写

//首字母大写方法可以被外部访问,小写就不行
//首字母大写方法可以被反射获取,小写不行(还没找到解决方法)

6、案例

速率限制

//控制资源的使用速率(规定多久重复执行一次)
package mainimport ("fmt""time"
)func main() {//第一部分 重复速率限制requests := make(chan int, 5)for i := 1; i <= 5; i++ {requests <- i //赋值5次}close(requests)limiter := time.Tick(200 * time.Millisecond) //200毫秒的打点器(速率)for req := range requests { //输出<-limiter //启动打点器fmt.Println("request", req, time.Now()) //打印结果}//第二部分 运行变数速率限制burstyLimiter := make(chan time.Time, 3) //核心channel 存储3个定时器for i := 0; i < 3; i++ {burstyLimiter <- time.Now() //存储3个没用限制定时器}go func() {for t := range time.Tick(200 * time.Millisecond) {//存储200毫秒的打点器(速率)burstyLimiter <- t //因为核心chan存满了,所以会进入堵塞}}()burstyRequests := make(chan int, 5)//关键channel,最大存储5次for i := 1; i <= 5; i++ {burstyRequests <- i//赋值5次}close(burstyRequests)for req := range burstyRequests {//受关键channel影响,只能读5次,所以只会对堵塞的burstyLimiter赋值2次<-burstyLimiter //取出核心channel,解除堵塞fmt.Println("request", req, time.Now())}
}

加密

//SHA1(散列)加密func main() {//SHA1 散列(hash)创建新的散列,可以应用于加密(需要三步骤 sha1.New(),h.Write,h.Sum)s := "sha1 this string"s2 := "this this this"h := sha1.New() //md5加密类似md5.New()h.Write([]byte(s))//处理字符串为切片bs := h.Sum(nil)//得到最终的散列值的字符切片,可以追加额外的字节切片,一般不会用h.Reset()//每次加密一个字符串需要Reset,生成一个新的散列h.Write([]byte(s2))fmt.Printf("%x\n",h.Sum(nil))fmt.Printf("%x\n", bs)
}
//base64 编解码
func main() {data := "abc123!?$*&()'-=@~"sEnc := b64.StdEncoding.EncodeToString([]byte(data)) //编码 string转base64fmt.Println(sEnc)sDec, _ := b64.StdEncoding.DecodeString(sEnc) //解码 base64转stringfmt.Println(string(sDec))fmt.Println()uEnc := b64.URLEncoding.EncodeToString([]byte(data))fmt.Println(uEnc)uDec, _ := b64.URLEncoding.DecodeString(uEnc)fmt.Println(string(uDec))
}

读写文件

//读文件
package mainimport ("bufio""fmt""io""io/ioutil""os"
)func main() {read2()
}func check(e error) {if e != nil && e != io.EOF{panic(e)}
}//方法一
func read(){f, err := os.Open("./a.txt") //打开一个文件check(err)defer f.Close() //处理结束后关闭文件r := bufio.NewReader(f) //文件读取到Reader中buf :=make([]byte,8)//每次读取多少var sum []byte//用来存储每次读取的bytefor  {//r.Seek(offset, whence) //更改选中光标【参数1:偏移量】【参数2:0从头,1当前,2末尾】n, err := r.Read(buf)check(err)if n == 0{break}//buf... == buf[0],buf[1]...sum = append(sum, buf...)}fmt.Println(string(sum))
}//方法二
func read1(){//一次性读取适合读取内容比较小的文件//一次性读取文件f, err := ioutil.ReadFile("./a.txt") //一次性读取文件,返回是byte[]check(err)fmt.Println(string(f))
}//方法三
func read2() {//读取到file中,再利用ioutil将file直接读取到[]byte中, 这是最优f, err := os.Open("./a.txt")check(err)defer f.Close()fd, err := ioutil.ReadAll(f)check(err)fmt.Println(string(fd))
}
//写文件
package mainimport ("bufio""fmt""io""io/ioutil""os"
)func checks(e error) {if e != nil && e != io.EOF{panic(e)}
}func main() {write3()
}//方法一
func write(){d1 := []byte("eeeeeeee")err := ioutil.WriteFile("./a.txt",d1,0777)checks(err)reads()
}//方法二
func write1(){f, err := os.OpenFile("./a.txt", os.O_APPEND, 0666) //以追加模式打开文件//os.Create(filename) //文件不存在,可以使用这个checks(err)defer f.Close()_, err = io.WriteString(f, "\nccccccccc")checks(err)reads()
}//方法三
func write2(){f, err := os.Create("./b.txt") //创建文件checks(err)defer f.Close()_, err = f.Write([]byte("AAAAA")) //写入文件(字节数组)checks(err)
}//方法四
func write3(){f, _:= os.Create("./c.txt")//创建文件defer f.Close()w := bufio.NewWriter(f) //创建新的 Writer 对象w.WriteString("bufferedn") //写入字符串w.Flush()f.Close()
}func reads() {f, err := os.Open("./a.txt")checks(err)defer f.Close()fd, err := ioutil.ReadAll(f)checks(err)fmt.Println(string(fd))
}

键盘输入

func main() {scanner := bufio.NewScanner(os.Stdin) //获取键盘输入流for scanner.Scan() { //堵塞ucl := strings.ToUpper(scanner.Text())//获取键盘输入的文字fmt.Println(ucl)}if err := scanner.Err(); err != nil {fmt.Fprintln(os.Stderr, "error:", err)os.Exit(1)}
}

文件目录

//跨平台文件路径(根据操作系统构建目录路径)
//如Linux 下的 dir/file 和 Windows 下的 dir\file 。
func main() {p := filepath.Join("dir1", "dir2", "filename","Q.TXT")//拼接为路径fmt.Println("p:", p)//结果:p: dir1\dir2\filenamefmt.Println(filepath.Join("dir1//", "filename"))//Join会自动去除删除多余的分隔符和目录fmt.Println(filepath.Join("dir1/../dir1", "filename"))fmt.Println("Dir(p):", filepath.Dir(p))//获取文件父级路径fmt.Println("Base(p):", filepath.Base(p))//获取当前选中的文件或者文件夹fmt.Println(filepath.IsAbs("dir1/dir2"))//是否是绝对路径fmt.Println(filepath.Split(p)) //路径分解为父级路径和当前文件或目录filename := "config.json"ext := filepath.Ext(filename)//获取文件后缀fmt.Println(ext)fmt.Println(strings.TrimSuffix(filename, ext))//删除字符串里的ext字符rel, err := filepath.Rel("a/b/file", "a/b/t/file")//两者之间的相对路径if err != nil { panic(err)}fmt.Println(rel)rel, err = filepath.Rel("a/b", "a/c/t/file")if err != nil {panic(err)}fmt.Println(rel)
}
package mainimport ("fmt""io/ioutil""os"
)func main() {readdir()
}//删除文件
func rm(){path := "a.txt"err := os.Remove(path) //删除当前目录下的文件if err!=nil {fmt.Println("file not found ")}
}//删除文件夹
func rmdir(){err := os.Mkdir("a", 0666) //创建文件if err!=nil {fmt.Println("file create fail")}defer os.RemoveAll("a") //删除整个目录
}//列出文件夹下全部文件
func readdir(){getwd, _ := os.Getwd()fmt.Println("当前路径",getwd) //获取当前路径dir, err := ioutil.ReadDir("pkg") //获取目录下全部文件if err!=nil {fmt.Println("not fileDir")}for _,i := range dir {fmt.Println(i.Name(),"----",i.IsDir())}
}

timer(定时器)

//定时器
package main
import ("fmt""time"
)func main() {timer := time.NewTimer(time.Second*1)//创建一个指定时长的定时器fmt.Println("倒计时:",time.Now())go func() {t := <- timer.C //定时器到点执行fmt.Println("时间到:",t)}()timer.Stop() //停止定时器(手动停止)time.Sleep(2 * time.Second)
}

ticker(打点器)

//打点器 (循环的定时器,每到指定时长就运行一次)
package mainimport ("fmt""time"
)func main() {ticker := time.NewTicker(time.Second*1)//创建一个指定时长的打点器fmt.Println("开始时间:",time.Now())done := make(chan bool)go func() {for {select { case <-done:returncase t := <-ticker.C://获取打点器并到点执行fmt.Println("打卡:",t)}}}()time.Sleep(5*time.Second)ticker.Stop() //停止打点器(手动停止)done <- truefmt.Println("结束")
}

web

package mainimport ("fmt""log""net/http"
)type Hello struct{}
type String string
func(s String) ServeHTTP(w http.ResponseWriter, r *http.Request){fmt.Fprintln(w, "Method:",r.Method) //获取请求方法//r.PostFormValue["text"]获取多个参数(如:复选框)fmt.Fprintln(w, "Post_Param:",r.PostFormValue("text"))//获取单个Post参数fmt.Fprintln(w, "Get_Param:",r.URL.Query()) //获取Get参数列表,获取单个get参数query["key"][0]fmt.Fprintln(w, "header:",r.Header)//获取请求头fmt.Fprintln(w, "RemoteAddr:",r.RemoteAddr)//获取远程主机fmt.Fprintln(w, "url:",r.URL)//获取请求地址
}func (h Hello) ServeHTTP(w http.ResponseWriter,r *http.Request) {fmt.Fprintln(w, "method:",r.Method)
}func main() {http.Handle("/string",String("abc")) //添加对应的处理ServeHTTPhttp.Handle("/hello",Hello{})//http.HandlerFunc() //添加对应的处理函数err := http.ListenAndServe("localhost:4000", nil)//web监听器if err != nil {log.Fatal(err)}
}

接受退出信号

func main() {sigs := make(chan os.Signal, 1)done := make(chan bool, 1)signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)//signal.Notify 注册给定的通道,用于接收特定信号go func() {sig := <-sigs //接受退出信息fmt.Println()fmt.Println(sig)done <- true //结束堵塞}()fmt.Println("awaiting signal")<-done //解除堵塞fmt.Println("exiting")
}

Golang快速入门上手相关推荐

  1. python多久能上手_小白学习Python,怎样能够快速入门上手

    原标题:小白学习Python,怎样能够快速入门上手 时至今日,Python已经成为最受欢迎的编程语言之一,清晰易读,适用广泛.在TIOBE 排行榜中位居第四,成为名副其实的人工智能第一语言. 那么零基 ...

  2. 【Golang 快速入门】项目实战:即时通信系统

    Golang 快速入门 即时通信系统 - 服务端 版本一:构建基础 Server 版本二:用户上线功能 版本三:用户消息广播机制 版本四:用户业务层封装 版本五:在线用户查询 版本六:修改用户名 版本 ...

  3. 【Golang 快速入门】高级语法:反射 + 并发

    Golang 快速入门 Golang 进阶 反射 变量内置 Pair 结构 reflect 结构体标签 并发知识 基础知识 早期调度器的处理 GMP 模型 调度器的设计策略 并发编程 goroutin ...

  4. golang快速入门[8.3]-深入理解IEEE754浮点数

    前文 golang快速入门[1]-go语言导论 golang快速入门[2.1]-go语言开发环境配置-windows golang快速入门[2.2]-go语言开发环境配置-macOS golang快速 ...

  5. 快速入门上手第一课 | 从云计算到 Serverless

    一. 从云计算到 Serverless 自世界上第一台通用计算机ENIAC(图左)诞生以来,计算机科学与技术的发展就从未停止过前进的脚步.2003年-2006年,谷歌先后发表了这三篇非常经典的论文(图 ...

  6. golang快速入门--语言基础

    语言基础语法 行分隔符 在golang中,多个语句写在同一行,必须使用分号 " ; " 分隔开 注释 单行注释 使用// 即可表示 多行注释 使用/-/ 表示 字符串连接 允许使用 ...

  7. 【探花交友】学习MongoDB快速入门上手

    目录 2.MongoDB简介 1.1.MongoDB简介 1.2.MongoDB的特点 1.3 数据类型 3.MongoDB入门 2.1.数据库以及表的操作 2.2.新增数据 2.3.更新数据 2.4 ...

  8. 【Vue3】vue3中组合式Api的setup写法快速入门上手起步

    要使用Vue3,那必须得会setup,因为setup是组合式API表演的舞台. 安装volar 如果你的VScode之前安装有vuter插件,请先把他禁用或者卸载掉,然后安装volar. 因为,vut ...

  9. golang快速入门--爬虫--基于colly框架的爬虫案例

    colly爬虫框架 colly是用go实现的网络爬虫框架 这个框架与python的scrapy框架很像 数据清洗时,可以像jquery中一样用选择器来选择web元素 同时,清洗数据也可以使用xpath ...

最新文章

  1. git保姆级入门(包含解决git仓库报错500的问题)
  2. 并发编程-10线程安全策略之不可变对象
  3. 分享一款好用的PHP下ID混淆插件
  4. Android中集成Jpush实现推送消息通知与根据别名指定推送附示例代码下载
  5. WebStorm 10支持TypeScript 1.4到JavaScript的实时编译
  6. 解决升级Spark2.0之后,DataFrame map操作报错
  7. 《统计学习方法》P74勘误
  8. 使用Synergy多台电脑共享键盘鼠标和剪贴板
  9. java 鼠标精灵_纯Java实现跨平台鼠标键盘模拟、找图找色,Java版按键精灵
  10. 485串口测试工具软件下载_串口调试助手详细讲解(结合实操),通讯问题不再是问题...
  11. html table设置行高_字号与行高
  12. 微软再现宕机事故 部分用户9天无法使用电邮
  13. mt4交易软件云服务器_MT4软件使用教程1常见货币对交易图表类型
  14. 520表白网页代码html 爱心网页制作
  15. 苹果vs剪辑下载_Vlog教程 | 如何在手机剪辑app中添加自己的音乐?
  16. 常用的计算机硬件软件英语,计算机英语常用词汇.ppt
  17. 我的世界服务器连接协议,go-mc: Minecraft(我的世界)各种协议的Go实现
  18. vue3+ts实现todolist功能
  19. ZCMU-1635- 超大型 LED 显示屏
  20. Filter基础知识

热门文章

  1. Ubuntu 18实现有线 无线同时用
  2. windows系统迁移工具
  3. 微信扫码登陆功能(保姆级)
  4. npoi html富文本,c#NPOI导出
  5. PaddleDetection-新增模型算法
  6. .net mysql transactionscope_TransactionScope和SQLite数据库被锁定
  7. linux pm,Kali Linux下配置PM3运行环境
  8. 万能程序员时代来临!
  9. 开源 java CMS - FreeCMS2.8 静态化管理
  10. 如何应对网络恶意的攻击行为?