2023年将会持续于B站、CSDN等各大平台更新,可加入粉丝群与博主交流:838681355,为了老板大G共同努力。
【商务合作请私信或进群联系群主】
Golang(Google):静态强类型、编译型、并发型、垃圾回收
具有python开发效率、又有C的高性能
严格区分大小写
环境变量设置:
系统变量新建GOROOT,变量值C:\Program Files\Go\ -> 修改PATH C:\Program Files\Go\bin
更换源:
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
go项目结构:
src:源代码文件
pkg:包文件
bin:相关bin文件
运行go项目:go run main.go
打包go项目:go build main.go
代码内容格式化:go fmt main.go
# 程序由main开始执行
package main (声明代码所属的main包)
import ("fmt") (所需要使用的包叫fmt)
func main() (声明一个main()函数)
{fmt.Println("Hello,playgounrd")}
1.自动立即回收。
2.更丰富的内置类型。
3.函数多返回值。
4.错误处理。
5.匿名函数和闭包。
6.类型和接口。
7.并发编程。
8.反射。
9.语言交互性。
Go的函数、变量、常量、自定义类型、包(package)的命名方式遵循以下规则:
标识符组成:
1.由数字、字母下划线(_)组成
2.只能数字下划线(_)开头
3.标识符区分大小写
关键字:
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
保留字:
Constants: true false iota nil
Types: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
Functions: make len cap new append copy close delete
complex real imag
panic recover
var(声明变量) var 变量名 变量类型
const(声明常量)
type(声明类型)
func(声明函数)
:= 短变量声明(只能放在函数内部)
引用类型(指针):
slice -- 序列数组(最常用)
map -- 映射
chan -- 管道
内置函数:
append -- 用来追加元素到数组、slice中,返回修改后的数组、slice
close -- 主要用来关闭channel
delete -- 从map中删除key对应的value
panic -- 停止常规的goroutine (panic和recover:用来做错误处理)
recover -- 允许程序定义goroutine的panic动作
real -- 返回complex的实部 (complex、real imag:用于创建和操作复数)
imag -- 返回complex的虚部
make -- 用来分配内存,返回Type本身(只能应用于slice, map, channel)
new -- 用来分配内存,主要用来分配值类型,比如int、struct。返回指向Type的指针
cap -- capacity是容量的意思,用于返回某个类型的最大容量(只能用于切片和 map)
copy -- 用于复制和连接slice,返回复制的数目
len -- 来求长度,比如string、array、slice、map、channel ,返回长度
print、println -- 底层打印函数,在部署环境中建议使用 fmt 包
内置结构error:
type error interface { //只要实现了Error()函数,返回值为String的都实现了err接口
Error() String
}
算术运算符:+ - * / %
关系运算符:== != > >= < <=
逻辑运算符:&& || !
位运算符:& 1 ^ >> <<
赋值运算符:= += -= *= /= %= <<= >>= &= 1= ^=
func main() {
buf := make([]byte, 1024)
f, _ := os.Open("/Users/***/Desktop/text.txt")
// 比如os.Open,返回值为*os.File,error, 普通写法是f,err := os.Open("xxxxxxx"),如果此时不需要知道返回的错误值就可以用f, _ := os.Open("xxxxxx")如此则忽略了error变量
defer f.Close()
for {
n, _ := f.Read(buf)
if n == 0 {break}os.Stdout.Write(buf[:n])}}
数组定义:var a [len]int
切片的定义:var 变量名 []类型,比如 var str []string var arr []int
[...]省略数组长度,做初始化处理
func main(){
var a = [5]int{1,2,3,4,5}
for i, v := range a{
fmt.Printf("i:%d v:%v\n", i , v)
}
}
示例一:
func main(){
var a = []int{1,2,3,4,5}
for _, v :=range a{
fmt.Printf("%v\n", v)
}
}
示例二:
func main(){
var s2 []int
var s2 = make([]int,2)
fmt.Printf("s2:%v\n",s2)
}
// 添加
func addtest(){
var s1 = []int{}
s1 = append(s1,100)
s1 = append(s1,200)
s1 = append(s1,300)
fmt.Print(s1)
}
// 删除
func delecttest(){
var s1 = []int{1,2,3,4,5}
s1 = append(s1[:0],s1[:2]...)
// a = append(a[:index],a[index+1]...)
fmt.Print(s1)
}
// 修改
func update(){
var s1 = []int{1,2,3,4}
s1[1] = 100
fmt.Print(s1)
}
// 查询
func query(){
var s1 = []int{1,2,3,4}
var key = 2
for i , v := range s1{
if v == key{
fmt.Printf("i:%v\n",i)
}
}
}
// 复制
func copy(){
var s1 = []int{1,2,3,4}
var s2 = s1
s2[0] = 100
fmt.Printf("s2,%v",s2)
}
两个符号:&(取地址)、*(根据地址取值)
类型指针不能偏移和运算。
指针地址:
func main() {
//指针取值
a := 10
b := &a // 取变量a的地址,将指针保存到b中
fmt.Printf("type of b:%T\n", b)
c := *b // 指针取值(根据指针去内存取值)
fmt.Printf("type of c:%T\n", c)
fmt.Printf("value of c:%v\n", c)
}
实例:
func main(){
var a int = 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量存储地址 */
fmt.Printf("a的变量地址为:%x\n",&a)
fmt.Printf("ip变量储存的指针地址:%x\n",ip)
fmt.Printf("*ip变量的值:%d\n",*ip)
}
语法:
var ptr [MAX]*int; //表示数组里面的元素的类型是指针类型
实例:
func main(){
a := [3]int{1,2,3}
var pa [3]*int
fmt.Printf("pa:%v\n",pa)
for i :=0 ; i
func main(){
fmt.Println("输入:")
var a string
fmt.Scanf("%s",&a)
fmt.Println(a)
}
func main(){
s1 := "tom"
s2 := "hello"
s3 := s1+s2
fmt.Printf("%s", s3)
}
func main(){
var buffer bytes.Buffer
buffer.WriteString("tom")
buffer.WriteString(",")
buffer.WriteString("20")
fmt.Printf("buffer.String():%v\n",buffer.String())
}
示例一:
func f(){
for i:=0 ; i<10 ; i++{ // i等于0,i小于10时,每次循环i+1
fmt.Println(i)
}
}
示例二:
func f(){
i:=0
for ; i<10 ; i++{ // i等于0,i小于10时,每次循环i+1
fmt.Println(i)
}
}
func main(){
a := [...]int{1,2,3,4}
fmt.Println(a)
var b = [...]string{"北京","上海","中山"}
fmt.Println(b)
for _,c := range b{
fmt.Println(c)
}
}
func f(){
for {
fmt.Println("循环")
}
}
break:跳出第一层循环
continue: 继续循环
Goto:跳出多层循环
func main(){
i := 1
if i >= 2 {
fmt.Println("2")
} else {
goto END
}
END:
fmt.Println("END....")
}
type person struct{
name string
age int
city string
}
func main(){
var p1 person
p1.name="123"
p1.city="ch"
p1.age=1
fmt.Println(p1.name,p1.city,p1.age)
}
type hello interface{ // 声明接口hello
say()
}
type dog struct{} //结构体dog
type cat struct{} //结构体cat
func (d dog) say(){ // 用dog调用say(),实现接口hello
fmt.Print("111")
}
func (c cat) say(){ // 用cat调用say(),实现接口hello
fmt.Print("222")
}
func main(){
var x hello // 声明一个hello类型得变量x
b := dog{} // 实例化dog赋予b
c := cat{} // 实例化cat赋予c
x = b // 将b赋予变量x
x.say()
x = c
x.say()
}
示例一:
func main(){
ret,err := getCircleAreaII(-5)
if err!=nil{
fmt.Println(err)
}else{
fmt.Println("ret=",ret)
}
}
func getCircleAreaII(radius float32)(ret float32,err error) {
if radius < 0{
err = errors.New("傻鸟,半径不能为负")
return
}
ret = 3.14 * radius * radius
return
}
示例二:
//正确写法
if err != nil{
//错误处理
return //或者继续
}
//正常代码
func main() {
runtime.GOMAXPROCS(1) //设置协程调度只有一个P
wg := sync.WaitGroup{}
wg.Add(20)
for i := 0; i < 10; i++ {
go func() {
fmt.Println("A: ", i)
wg.Done()
}()
}
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println("B: ", i)
wg.Done()
}(i)
}
wg.Wait()
}
//https://studygolang.com/articles/21588?fr=sidebar
var wg sync.WaitGroup // 申明一个信号量的全局变量
func hello(i int) {
defer wg.Done() // goroutine结束就登记-1
fmt.Println(i)
}
func main() {
var begin =time.Now()
for i := 1; i < 9000; i++ {
wg.Add(1) // 启动一个goroutine就登记+1
go hello(i)
}
wg.Wait() // 等待所有登记的goroutine都结束再执行下一步
var elapseTime = time.Now().Sub(begin)
fmt.Println("耗时:", elapseTime)
}
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址:*sync.WaitGroup
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
}
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) { //这样子就不用定义全局变量
fmt.Println(i)
wg.Done()
}
单向通道的定义:
chan<- int是一个只能发送的通道,可以发送但是不能接收; 存入
<-chan int是一个只能接收的通道,可以接收但是不能发送。 取出.
定义的通道是否缓冲,需要看缓冲大小的值有没有定义。
make(chan 元素类型, [缓冲大小])
func main() {
// 原生字符串
buf := `
DOCTYPE html>
<html lang="zh-CN">
<head>
<title>C语言中文网 | Go语言入门教程title>
head>
<body>
<div>Go语言简介div>
<div>Go语言基本语法
Go语言变量的声明
Go语言教程简明版
div>
<div>Go语言容器div>
<div>Go语言函数div>
body>
html>
`
//解释正则表达式
reg := regexp.MustCompile(`<div>(?s:(.*?))div>`)
if reg == nil {
fmt.Println("MustCompile err")
return
}
//提取关键信息
result := reg.FindAllStringSubmatch(buf, -1)
//过滤<>>
for _, text := range result {
fmt.Println("text[1] = ", text[1])
}
}
https://blog.csdn.net/tianlongtc/article/details/80163661#:~:text=Go%E6%98%AF%E8%87%AA%E5%B8%A6runtime%E7%9A%84%E8%B7%A8%E5%B9%B3%E5%8F%B0%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%EF%BC%8CGo%E4%B8%AD%E6%9A%B4%E9%9C%B2%E7%BB%99%E8%AF%AD%E8%A8%80%E4%BD%BF%E7%94%A8%E8%80%85%E7%9A%84tcp%20socket%20api%E6%98%AF%E5%BB%BA%E7%AB%8BOS%E5%8E%9F%E7%94%9Ftcp%20socket%E6%8E%A5%E5%8F%A3%E4%B9%8B%E4%B8%8A%E7%9A%84%E3%80%82,%E7%94%B1%E4%BA%8EGo%20runtime%E8%B0%83%E5%BA%A6%E7%9A%84%E9%9C%80%E8%A6%81%EF%BC%8Cgolang%20tcp%20socket%E6%8E%A5%E5%8F%A3%E5%9C%A8%E8%A1%8C%E4%B8%BA%E7%89%B9%E7%82%B9%E4%B8%8E%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%96%B9%E9%9D%A2%E4%B8%8EOS%E5%8E%9F%E7%94%9F%E6%8E%A5%E5%8F%A3%E6%9C%89%E7%9D%80%E4%B8%80%E4%BA%9B%E5%B7%AE%E5%88%AB%E3%80%82
注意点:
err = msg.WriteMsg(conn,loginMsg);
if err != nil{
return
}
同等于:if err = msg.WriteMsg(conn, loginMsg); err != nil {return}
示例:
func main(){
x := 0
if n := "abc"; x>0{
fmt.Println(n[2])
}else if x<0{
fmt.Println(n[1])
}else{
fmt.Println(n[0])
}
}
func main(){
var a int = 100
var b int = 200
if a == 100{
if b == 200{
fmt.Printf("yes")
}
}
fmt.Printf("%d",a)
}
func main(){
var grade string = "8"
var marks int = 90
switch marks{
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" )
}
fmt.Printf("你的等级是 %s\n", grade )
}
func main(){
age := 18
gender := "男"
if age >= 18 && gender == "男"{
fmt.Println("成年")
}
}
函数:defer()
特性:先进后出
func main() {
var whatever [5]struct{}
for i := range whatever {
defer fmt.Println(i)
}
}
map是一种key:value键值对的数据结构容器。map内部实现哈希表。
map最重要一点通过Key来快速检索数据,key类似于索引,指向数据的值。
map是引用类型。
格式:
/*声明变量,默认map是nil*/
var map_variable map[key_data_type]value_data_type
/*使用Make函数*/
map_variable = make(map[key_data_type]value_data_type)
map_variable: map变量名称
key_data_type: key的数据类型
value_data_type: 值得数据类型
声明使用:
func maptest(){
var m map[string]string
m = make(map[string]string)
m["name"] = "tom"
m["age"] = "18"
m["email"] = "[email protected]"
for key, value := range m {
fmt.Print(key+":"+value+" ")
}
}
遍历:
func maptest(){
var m map[string]string
m = make(map[string]string)
m["name"] = "tom"
m["age"] = "18"
m["email"] = "[email protected]"
for key, _ := range m {
fmt.Print(key+":"+" ")
}
}
1.3种函数:普通函数、匿名函数、方法函数
2.不允许函数重载(同名)
3.不能嵌套函数但可嵌套匿名函数
4.函数参数可以无名称
语法调用:
func function_name([parameter list]){return_types}
{
函数体
}
解析:
func:函数声明
function_name:函数名称
[parameter list]:参数列表,当函数被调用时,将值传递给参数。
return_types:返回类型,函数返回一列值。
示例:
func sum(a int, b int)(ret int){
ret = a+b
return ret
}
func main(){
r := sum(1,2)
fmt.Print(r)
}
func main(){
r := sum(1,2)
fmt.Print(r)
}
有返回值实例:
func sum(a int, b int)(ret int){
ret = a+b
return ret
}
func main(){
r := sum(1,2)
fmt.Print(r)
}
无返回值实例:
func sum(){
fmt.Print("hello")
}
func main(){
sum()
}
多个返回值实例:
func sum()(name string,age int){
name="hello"
age=18
return //也等于return name,age
}
func main(){
n,a := sum()
fmt.Print(n,a)
}
func sum(a int,b int)int{ //形参
return a+b
}
func f1(a int){ // Copy
a = 100
}
func f2(s []int){ // 切片替换
s[0] = 1000
}
func main(){
s := []int{1,2,3}
f2(s)
fmt.Print(s)
}
func test(args ...int){ // 多参数遍历
for _,v := range args{
fmt.Print(v)
}
}
func main(){
test(1,2,3,4)
test(22,11,33)
}
type定义函数类型:
type fun func(int,int)int // 定义一个fun函数类型,接受两个int类型参数,返回int返回值
实例:
func sum(a int,b int)int{
return a+b
}
func max(a int,b int)int{
if a>b{
return a
}else{
return b
}
}
func main(){
type test123 func(int,int)int
var test test123
test = max
r := test(1,2)
fmt.Print(r)
}
go语言函数不能嵌套,但是在函数内部可以定义匿名函数,实现一下简单功能调用。
语法格式:
func (参数列表)(返回值)
可以既没有参数也没有返回值
实例:
func main(){
max := func(a int, b int) int{
if a>b{
return a
} else{
return b
}
}
i := max(1,2)
fmt.Print(i)
}
定义在一个函数内部的函数。本质上,闭包是将函数内部和函数外部连接起来的桥梁,胡总和说是函数和其引用环境的组合体。
闭包 = 函数 + 引用环境
实例:
func add()func(y int)int{
var x int
return func(y int) int{
x += y
return x
}
}
func main(){
f := add()
r := f(10)
fmt.Print(r)
fmt.Print(f(20))
}
1. 递归就说自己调用自己
2. 必须先定义函数的推出条件,没有退出条件将进入死循环
3. go语言递归可能会产生一大堆goroutine,也可能出现空间内存溢出问题
实例:
func test(a int ) int {
if a == 1{ //退出条件
return 1
}else{ // 自己调用自己
return a * test(a-1)
}
}
func main(){
i := test(5)
fmt.Print(i)
}
defer语句会将后面跟随的语句进行延迟处理。
特性:
1. 关键字defer用于注册延迟调用
2. 这些调用直到return前才被执行。因此可以做资源清理
3. 多个defer语句,按先进后出的方式执行
4. defer语句中的变量,defer声明时已经决定
用途:
1.关闭文件句柄
2.锁资源释放
3.数据库连接释放
实例:
func test() {
fmt.Print("start...")
defer fmt.Print("start...") // 后执行
fmt.Print("start...")
fmt.Print("start...")
fmt.Print("start...")
fmt.Print("end...")
}
start...start...start...start...end...start...
init函数,先于main函数执行,实现包级别的一些初始化操作
特点:
1.init函数先于Main函数自动主席那个,不能被其它函数调用
2.init函数没有输入参数,返回值;
3.每个包可以有多个函数
4.包的每个源文件也可以有多个init函数,这点比较特殊;
5.同一个包的init执行顺序,golang没有明确定义,编程时要注意程序不要以来这个执行顺序
6.不同包的init函数按照包导入的依赖关系决定执行顺序
实例:
func init(){
fmt.Print("init...")
}
func main(){
fmt.Print("main...")
}
类型定义:type NewType Type // 相当于定义了一个全新的类型
类型别名:type NewType = Type // 没有定义一个新的类型,只是使用另一个别名替换之前的类型
go语言没有面向对象概念,但是可以使用结构体实现。
与类型定义,结构体定义和类型定义类似,关键字:struct
语法结构:
type struct_variable_type struct{
member definition;
member definition;
...
member definition;
}
type: 结构体定义关键字
struct_variable_type:结构体类型名称
struct: 结构体定义关键字
member definition;: 成员定义
实例:
type Person struct{ // 自定义了一个类型,类似int
id int
name string
age int
email string
}
func main(){ // 访问结构体成员
var tom Person // 声明是结构体类型的,类似var i int
tom.id = 1
tom.age = 18
tom.name = "tom"
fmt.Print(tom.id)
fmt.Print(tom.age)
fmt.Print(tom.name)
}
func main(){
var tom struct{
id int
name string
age int
}
tom.id = 102
tom.age = 18
tom.name = "tom"
fmt.Printf("tom:%v",tom)
}
func main(){
type Person struct{
id int
name string
age int
email string
}
var tom Person
tom = Person{
id: 101,
name: "tom",
age: 20,
email: "[email protected]",
}
fmt.Printf("%v",tom)
}
func test2(){
type Person struct{
id int
name string
age int
}
tom := Person{
id: 101,
name: "tom",
age: 20,
}
var p_person *Person
p_person = &tom
fmt.Printf("tom:%v\n",tom)
fmt.Printf("p_person:%v\n",p_person)
fmt.Printf("p_person:%v\n",*p_person)
}
new关键字创建结构体指针:
func test2(){
type Person struct{
id int
name string
age int
}
var tom = new(Person)
fmt.Printf("tom:%v\n",tom)
}
go结构体可以像普通变量一样,作为函数的参数,传递给函数:
1.直接传递结构体,函数内部不会改变外面结构体内容
2.传递结构体指针,函数内部能够改变外部结构体内容
直接传递结构体:
type Person struct{
id int
name string
}
func showPerson(per Person){
per.id = 101
per.name = "kite"
fmt.Printf("per:%v",per)
}
func main(){
showPerson(Person{})
}
指针传递结构体:
type Person struct{
id int
name string
}
func showPerson(per *Person){
per.id = 101
per.name = "kite"
fmt.Printf("per:%v",per)
}
func main(){
tom := Person{
id : 100,
name : "tom",
}
per := &tom
showPerson(per)
}
func main(){
type Dog struct{
name string
age int
color string
}
type Person struct{
dog Dog
name string
age int
}
dog := Dog{
name:"hellO",
age:2,
color:"black",
}
per := Person{
dog : dog,
name:"tom",
age:20,
}
fmt.Printf("per:%v",per)
}
通过.来访问:
fmt.Printf("per:%v",per.dog.name)
go语言没有面向对象方法,没有类对象概念,但可以使用结构体模拟这些特性。
go方法是一种特殊函数,定义于struct智商(与struct关联、绑定),被称为struct的接受者:方法就是有接收者的函数
语法格式:
type mytype struct{}
func (recv mytype) my_method(para) return_type{}
func (recv *mytype) my_method(para) return_type{}
实例:
type Person struct{
name string
}
//(per Person)接收者receiver
func (per Person) eat(){
fmt.Println("%v,eat...",per.name)
}
func (per Person) sleep(){
fmt.Println("%v,sleep",per.name)
}
type customer struct{
name string
}
func (customer customer) login(){
fmt.Println("%v,login",customer.name)
}
func main(){
per := Person{
name:"tom",
}
per.eat()
per.sleep()
pas := customer{
name:"tom",
}
pas.login()
}
结构体实例,有值类型和指针类型,方法接收者是结构体,也有值类型和指针类型。区别就说接收者是否复制结构体副本。值类型复制,指针类型不复制。
值类型结构体和指针类型结构体
实例:
func main(){
type Person struct{
name string
}
p1 := Person{
name:"tom",
}
p2 := &Person{
name:"tom",
}
fmt.Printf("p1:%T\n",p1)
fmt.Printf("p2:%T\n",p2)
}
go语言的接口,是一种新的类型定义,把所有具有共性的方法定义在一起,任何其它类型只要实现了这些方法就是实现了这个接口。
语法格式:
/* 定义接口 */
type interface_name interface{
method_name1 [return_type]
...
methond_namen [return_type]
}
/* 定义结构体 */
type struct_name struct{
/* variables */
}
/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type]{
/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type]{
/* 方法实现 */
}
实例:
// writer reader
type USB interface{ // 接口定义
read()
write()
}
type Computer struct{ // 定义结构体
name string
}
func (c Computer) read(){ // 方法
fmt.Printf("c.name: %v\n", c.name)
fmt.Println("read..")
}
func (c Computer) write(){
fmt.Printf("c.name: %v\n", c.name)
fmt.Println("write...")
}
func main(){
c := Computer{ // 定义
name:"tom",
}
c.read() //调用接口
c.write()
}
type Pet interface{
eat(string) string
}
type Dog struct{
name string
}
func (dog Dog) eat(name string) string{
dog.name = "hello..."
fmt.Printf("name: %v\n", name)
return "wow"
}
func main(){
dog := &Dog{
name:"hello...",
}
s := dog.eat("no")
fmt.Printf("s:%v\n",s)
fmt.Printf("dog: %v\n", dog)
}
一个类型实现多个接口:
(有一个player接口可以播放音乐,有一个Vieo接口可以播放视频,一个手机实现两个接口,可以放音乐和视频
多个类型实现一个接口)
type Player interface{
playMusic()
}
type Video interface{
playVideo()
}
type Mobile struct{}
func (m Mobile) playMusic(){
fmt.Printf("play music")
}
func (m Mobile) playVideo(){
fmt.Printf("play video")
}
func main(){
m := Mobile{}
m.playMusic()
m.playVideo()
}
多个类型实现一个接口:
type Pet interface{
eat()
}
type Dog struct{
}
type Cat struct{
}
func (dog Dog) eat(){
fmt.Println("dog eat...")
}
func (cat Cat) eat(){
fmt.Println("cat eat...")
}
func main(){
dog := Dog{}
dog.eat()
cat := Cat{}
cat.eat()
}
飞鱼:既能飞又能游
飞接口:
type Flayer interface{
fly()
}
游接口:
type swimmer interface{
swim()
}
整合实例:
type Fly interface{
fly()
}
type Swim interface{
swim()
}
// 接口组合
type Flyfish interface{
Fly
Swim
}
type Fish struct{}
func (fish Fish) swim(){
fmt.Println("swim")
}
func (fish Fish) fly(){
fmt.Println("fly")
}
func main(){
var ff Flyfish
ff = Fish{}
ff.fly()
ff.swim()
}
“开-闭”原则为OCP原则。
实例:
type Per interface{ //接口创建
eat()
sleep()
}
type Dog struct{} //接收者创建dog
type Cat struct{} //接收者创建cat
func (dog Dog) eat(){ // Dog 实现per接口
fmt.Println("dog eat...")
}
func (dog Dog) sleep(){
fmt.Println("dog sleep...")
}
func (cat Cat) eat(){ // cat 实现per接口
fmt.Println("cat eat...")
}
func (cat Cat) sleep(){
fmt.Println("cat sleep...")
}
type Person struct{}
func (person Person) care(pet Per){ // Per 既可以传递Dog也可以传递Cat
pet.eat()
pet.sleep()
}
func main(){
dog := Dog{}
cat := Cat{}
person := Person{}
person.care(dog)
person.care(cat)
}
golang无面向对象概念,没有封装概念,但可以通过结构体struct和函数绑定实现OOP的属性和方法等特性。接收者receiver方法。
例如:定义一个Person类,有name和age属性,有eat/sleep/work方法
实例:
type Person struct{
name string
age int
}
func (per Person) eat(){
fmt.Println("eat...")
}
func (per Person) sleep(){
fmt.Println("sleep...")
}
func (per Person) work(){
fmt.Println("work...")
}
func main(){
per := Person{
name:"tom",
age: 20,
}
fmt.Print(per)
per.eat()
per.sleep()
per.work()
}
结构体嵌套实现继承
实例:
type Animal struct{
name string
age int
}
func (a Animal) eat(){
fmt.Println("eat...")
}
func (a Animal) sleep(){
fmt.Println("sleep...")
}
type Dog struct{
a Animal // 理解为继承
color string
}
type Cat struct{
a Animal
bbb string
}
func main(){
dog := Dog{
Animal{name:"hello",age:2,},
"blue",
}
dog.a.eat()
dog.a.sleep()
fmt.Printf("dog.color: %v\n", dog.color)
fmt.Printf("dog.a.age: %v\n", dog.a.age)
}
使用函数来模拟构造函数功能
实例:
type Person struct{
name string
age int
}
func NewPerson(name string,age int) (*Person ,error){
if name==""{
return nil,fmt.Errorf("name = null")
}
if age<0 {
return nil,fmt.Errorf("age = null")
}
return &Person{name:"tom",age:20}, nil
}
func main(){
per,err := NewPerson("tom",20)
if err == nil{
fmt.Printf("per:%v\n",per)
}
}
包区分命名空间(一个文件夹中不能有两个同名文件),go中创建一个包,一般是创建一个文件夹,在该文件夹里里面的go文件中,使用package关键字声明包名称,通常文件夹名称和包名称相同,并且在同一个文件下main只有一个包。
创建包:
package dao //声明一个包名为dao
import "fmt" //调用fmt模块
func test1(){
fmt.Print("test")
}
导入包: (要使用某个包下面的变量或方法,需要导入该包,导入包时,要导入从GOPATH开始的包路径,例如,在service.go中导入dao包)
必须要有的三个文件夹:/src /pkg /bin
package main
import "dao" //调用名为dao的包
func test(){
fmt.Print("test package")
}
go modules用来管理模块中包的依赖关系。
go mod 使用方法:
* 初始化模块: go mod init <项目模块名称> // 必须使用
* 依赖关系处理,根据go.mod文件: go mod tidy // 下载一些依赖
* 将依赖包复制到项目下的vendor目录: go mod vendor
* 显示依赖关系: go list -m all
* 显示详细依赖关系: go list -m -json all
* 下载依赖: go mod download [path@version]
项目结构:
pro/dao/
--user_dao.go
pro/service/
--customer_service.go
--user_service.go
pro/utils/
--utils.go
pro/
--main.go
使用流程:
1.先在main.go目录下进行初始化 go mod init <项目名称文件夹>
2.在需要导入的包,例如service包,先进入cd pro/service/包中,用go build来进行导入包使用
3.在main.go中就可以使用Import{"pro/service"}来进行调用方法
/pro/service/user_service.go:
package service
import{
"fmt"
}
func TestService(){
fmt.Print("hello")
}
/pro/main.go:
package main
import{
"fmt"
"pro/service"
}
func main(){
fmt.Println("wow")
service.TestService()
}
Goroutines:并发处理操作一种方式。
使用方法: go tesk()
实例:
func show(msg string){
for i:=0; i<5; i++{
fmt.Printf("msg:%v",msg)
time.Sleep(time.Millisecond * 100)
}
}
func main(){ // 交替执行
go show("1") //启动了一个协程
show("2")
}
用于在goroutine之间共享数据,当执行goroutine之间共享资源或数据,通道充当goroutine之间的管道并提供机制来保证同步交换。
两种类型通道:
无缓冲通道:用于执行goroutine之间的同步通信。
缓冲通道:用于执行异步通信。
区别:无缓冲通道保证在发送和接受发生的瞬间执行两个goroutine之间的交换。缓冲通道没有这样的保证。
通道由make函数创建,该函数指定chan关键字和通道的元素类型。
语法:
Unbuffered := make(chan int) // 整形无缓冲通道
buffered := make(chan int, 10) // 整形有缓冲通道
使用内置函数Make创建无缓冲和缓冲通道,make第一个参数需要关键字chan,然后是通道允许交换的数据类型。
将值发送到通道代码块需要使用 <- 运算符:
语法:
goroutine1 := make(chan string,5) // 字符串缓冲通道
goroutine1 <- "Australia" // 通过通道发送字符串
通道接收值得代码块:<- 运算符附加到通道变量(goroutine1)的左侧,以接收来自通道的值
语法:
data := <-goroutine1 // 从通道接收字符串
通道的发送和接受特性:
1.对于同一个通道,发送操作之间是互斥的,接受操作之间也是互斥的
2.发送操作和接受操作中对元素值的处理是不可分割的
3.发送操作在完全完成之前会被堵塞。接受操作也是如此
实例:
package main
import (
"fmt"
"time"
"math/rand"
)
var values = make (chan int) // 创建int类型通道,只能传入int类型值
func send(){
rand.Seed(time.Now().UnixNano())
value := rand.Intn(10)
fmt.Printf("value: %v\n", value)
// time.Sleep(time.Second * 5)
values <- value
}
func main(){ // 从通道接收值
defer close(values)
go send()
fmt.Println("wait...")
value := <- values
fmt.Printf("value: %v\n", value)
fmt.Println("end...")
}
WaitGroup:还没执行完,稍等一会。
实例:
import (
"fmt"
"sync"
)
var wp sync.WaitGroup
func msg(i int){
defer wp.Done() // defer wp.add.(-1) 两条语句一样 goroutine结束就登记-1
fmt.Printf("i: %v\n", i)
}
func main(){
for i:=0; i<10; i++{
go msg(i) //启动一个协程来执行
wp.Add(1) //启动一个goroutine就登记+1
}
wp.Wait() //等待所有登记的goroutine都结束
// 主协程
fmt.Println("end...")
}
runtime:包内定义了一些协程管理相关的api
===================================================================================
runtime.Gosched():让出CPU时间片,重新等待安排任务
实例:
func show(msg string){
for i:=0; i<2; i++{
fmt.Printf("msg: %v\n", msg)
}
}
func main(){
go show("java") //子协程运行
for i:=0; i<2; i++{
runtime.Gosched() // 我有权力执行任务了,让给其它子协程来执行
fmt.Printf("golang:golang")
}
fmt.Println("end...")
}
===================================================================================
runtime.Goexit():退出当前协程
import (
"fmt"
"time"
"runtime"
)
func show(){
for i:=0; i<10; i++{
fmt.Printf("i: %v\n", i)
if i>=5{
runtime.Goexit() // 子线程大于5停止退出
}
}
}
func main(){
go show()
time.Sleep(time.Second)
}
===================================================================================
runtime.GOMAXPROCS:CPU核心线程设置
实例:
func a(){
for i := 0; i < 10; i++ {
fmt.Printf("a: %v\n", a)
time.Sleep(time.Millisecond * 100) // 睡一百毫秒
}
}
func b(){
for i := 0; i < 10; i++ {
fmt.Printf("b: %v\n", b)
}
}
func main(){
fmt.Println("runtime.NumCPU():%v\n",runtime.NumCPU())
runtime.GOMAXPROCS(1)
go a()
go b()
time.Sleep(time.Second)
}
snyc.Mutex: 通过互斥锁来实现同步操作
实例:
import (
"fmt"
"sync"
"time"
)
var i int = 100
var wg sync.WaitGroup
var lock sync.Mutex
func add(){
defer wg.Done()
lock.Lock()
i += 1
fmt.Printf("i++: %v\n", i)
time.Sleep(time.Millisecond *10)
lock.Unlock()
}
func sub(){
lock.Lock()
defer wg.Done()
i -= 1
fmt.Printf("i--: %v\n", i)
time.Sleep(time.Millisecond *2)
lock.Unlock()
}
func main(){
for i := 0; i < 100; i++ {
wg.Add(1)
add()
go add()
sub()
go sub()
}
wg.Wait()
fmt.Printf("end i: %v\n", i)
}
方法1:for循环+if判断
var c = make(chan int)
func main(){
go func(){
for i := 0; i < 5; i++ {
c <- i
}
close(c) // 一定要关闭通道,不然会造成死锁产生错误
}()
for {
v, ok := <-c
if ok {
fmt.Printf("v: %v\n", v)
}else{
break
}
}
}
===================================================================================
方法2:for range
var c = make(chan int)
func main(){
go func(){
for i := 0; i < 5; i++ {
c <- i
}
close(c) // 一定要关闭通道,不然会造成死锁产生错误
}()
for v := range c{
fmt.Printf("v: %v\n", v)
}
}
1.Select是go中的控制结构。类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,就会触发响应的动作。
select语句必须是一个channel操作
select中的default子句总是可运行
2.如果有多个case都可以运行,select会随机公平地选出一个执行,其它不会执行。
3.如果没有可运行地case语句,且有default语句,就会执行default动作
4.如果没有可运行地case语句,且没有default语句,select将阻塞,直到某个case通信可以运行。
实例:
import (
"fmt"
"time"
)
var chanInt = make(chan int,0)
var chanStr = make(chan string)
func main(){
go func(){
chanInt <- 100
chanStr <- "hell0"
defer close(chanInt)
defer close(chanStr)
}()
for{
select {
case r:= <- chanInt:
fmt.Printf("r: %v\n", r)
case r:= <- chanStr:
fmt.Printf("r: %v\n", r)
default:
fmt.Println("default...")
}
time.Sleep(time.Second)
}
}
Timer:定时器,实现定时操作,器内部也是通过channel来实现。
实例:
func main(){
//方法一:
timer := time.NewTimer(time.Second *2)
fmt.Printf("time.now():%v\n",time.Now())
t1 := <- timer.C // 阻塞的,指定时间到了
fmt.Printf("t2: %v\n", t1)
===================================================================================
//方法二:
timer1 := time.NewTimer(time.Second*2)
<-timer1.C
fmt.Printf("timer: %v\n", timer)
===================================================================================
//方法三: 如果只是单纯等待,用sleep.time实现
time.Sleep(time.Second)
===================================================================================
//方法四
<-time.After(time.Second *2)
fmt.Printf("...")
===================================================================================
//方法五
timer2 := time.NewTimer(time.Second)
go func(){
<- timer2.C
fmt.Println("...")
}()
s := timer.Stop()
if s{
fmt.Println("stop...")
}
time.Sleep(time.Second *3)
fmt.Println("func...")
}
===================================================================================
Timer只执行一次,Ticker可以周期执行。
实例:
func main(){
ticker := time.NewTicker(time.Second) // ticker周期性执行,两秒
counter := 1 //设置一个数为1
for _ = range ticker.C { //循环遍历
fmt.Println("ticker...") // 两秒周期输出ticker循环不停
counter++ //利用设置数来使周期的ticker停止
if counter <=5{
ticker.Stop()
break
}
}
}
import (
"fmt"
"sync/atomic" //原子操作包,跟互斥锁类似
"time"
)
var i int32 = 100
func add(){
atomic.AddInt32(&i,1)
}
func sub(){
atomic.AddInt32(&i,-1)
}
func main(){
for i := 0; i < 100; i++ {
go add()
go sub()
}
time.Sleep(time.Second *2)
fmt.Printf("i: %v\n", i)
}
atomic提供原子操作能够确保任一时刻只有一个goroutine对变量进行操作,善用atomic能够避免程序中出现大量的锁操作。
atomic常见操作:
* 增减
* 载入
* 比较并交换cas
* 交换
* 存储
atomic.AddInt32(&i,1) // 增减
fmt.Printf("i: %v\n",i)
atomic.AddInt32(&i,-1)
fmt.Printf("i: %v\n",i)
atomic.LoadInt32(&i) // read
fmt.Printf("i: %v\n", i)
atomic.StoreInt32(&i,200) // write
fmt.Printf("i: %v\n", i)
b := atomic.CompareAndSwapInt32(&i,100, 300) //cas
fmt.Printf("b: %v\n", b) // 如果有问题返回flase
fmt.Printf("i: %v\n", i)
os标准库实现平台(操作系统)无关的编程接口
// 创建文件
func createFile(){
f, err := os.Create("a.txt")
if err != nil{
fmt.Printf("err: %v\n", err)
}else{
fmt.Printf("f.Name():%v\n",f.Name())
}
}
// 创建目录
func makeDir(){
err := os.Mkdir("test",os.ModePerm) // 创建test目录,os.ModePerm赋予权限
if err != nil{
fmt.Printf("err: %v\n", err)
}
err2 := os.MkdirAll("a/b/c",os.ModePerm) // 创建多个目录
if err2 != nil{
fmt.Printf("err2: %v\n", err2)
}
}
// 删除目录
func deletDir(){
err := os.Remove("test.txt") //删除test文件
if err != nil{
fmt.Printf("err: %v\n", err)
}
os.RemoveAll("a") //删除整个目录
if err != nil{
fmt.Printf("err: %v\n", err)
}
}
// 获取工作目录
func wd(){
dir, _ := os.Getwd() //获取工作目录
fmt.Printf("dir: %v\n", dir)
os.Chdir("d:\"") //修改工作目录
s := os.TempDir() // 临时目录
fmt.Printf("s: %v\n", s)
}
// 重命名文件
func rename(){
err := os.Rename("test.txt","test2.txt") //将test.txt更名为test2.txt
if err != nil {
fmt.Printf("err: %v\n", err)
}
}
// 读文件
func readFile(){
b, err := os.ReadFile("test2.txt")
if err != nil{
fmt.Printf("err: %v\n", err)
}else{
fmt.Printf("b: %v\n", string(b[:]))
}
}
// 写文件
func writeFile(){
s := "hello world"
os.WriteFile("test2.txt",[]byte(s),os.ModePerm)
}
// 打开关闭软件
func openCloseFile(){
// 只读
f, _ := os.Open("test.txt")
fmt.Printf("f.Name():%v\n",f.Name())
f.Close()
// 读写或创建
f2, _ := os.OpenFile("test2.txt",os.O_RDWR|os.O_CREATE,0755)
fmt.Printf("f2.Name():%v\n",f2.Name())
err := f.Close()
fmt.Printf("err: %v\n", err)
err2 := f2.Close()
fmt.Printf("err2: %v\n", err2)
}
// 创建文件
func createFile(){
// 等价于,OpenFile(name,O_RDWR|O_CREATE|O_TRUNC,0666)
f,_ := os.Create("test3.txt")
fmt.Printf("f.Name(): %v\n", f.Name())
// 第一个参数 目录默认,Temp 第二个参数 文件名前缀
f2,_ := os.CreateTemp("","temp")
fmt.Printf("f2.Name(): %v\n", f2.Name())
}
// 读取文件
func readOps(){
// 循环读取
f,_ := os.Open("a.txt") // 打开文件
for {
buf := make([]byte,6) // 缓冲区
n,err := f.Read(buf) // 读到缓冲区里
fmt.Printf(string(buf))
fmt.Printf("n: %v\n", n)
if err == io.EOF{ // 读取字节中如果有EOF为空的字样,则跳出循环
break
}
}
f.Close()
// 从第几个开始读多少字节操作
buf := make([]byte,10)
f2,_ := os.Open("a.txt")
n,_ := f2.ReadAt(buf,5) // 从第五开始读十个
fmt.Printf("n: %v\n", n)
fmt.Printf("buf: %v\n", string(buf))
f.Close()
// 遍历目录
de,_ := os.ReadDir("a")
for _, v := range de{
fmt.Printf("v.IsDir():%V\n",v.IsDir())
fmt.Printf("v.Name():%V\n",v.Name())
}
// 定位读取
f3,_ := os.Open("a.txt")
f3.Seek(3,0)
buf2 := make([]byte,5)
n2,_ := f3.Read(buf)
fmt.Printf("n: %v\n", n2)
fmt.Printf("buf: %v\n", string(buf2))
f.Close()
}
// 写入文件操作
func write() {
//f,_ := os.OpenFile("test.go") // 打开文件,写入但并不清除原来的内容弄个
f,_ := os.OpenFile("a.txt",os.O_RDWR|os.O_TRUNC,0755) //清除原来的内容并把写入内容替换
f.Write([]byte("hello world")) // 写入的内容"hello world"
f.Close()
}
// 定位写入文件
func writeString(){
f,_ := os.OpenFile("a.txt",os.O_RDWR|os.O_TRUNC,0755)
f.WriteAt([]byte("abc"),3) // 在文件第三个字节中插入abc
f.Close()
}
// 获取当前正在运行的进程id
fmt.Printf("os.Getpid():%v\n",os.Getpid())
// 父id
fmt.Printf("os.Getpidd():%v\n",os.Getppid())
// 设置新进程的属性
attr := &os.ProcAttr{
//files指定新进程继承的活动文件对象
//前三个分别为,标准输入、标准输出、标准错误输出
Files:[]*os.File{os.Stdin, os.Stdout, os.Stderr},
//新进程的环境变啊零
Env: os.Environ(),
}
// 开启一个新进程
p, err := os.StartProcess("C:\\windows\\System32\\notepad.exe",[]string{"C:\\Windows\\System32\\notepad.exe","D:\\a.txt"},attr)
if err != nil{
fmt.Println(err)
}
fmt.Println(p)
fmt.Println("进程ID:",p.Pid)
// 通过线程ID查找进程
p2, _ := os.FindProcess(p.Pid)
fmt.Println(p2)
//等待10秒,执行函数
time.AfterFunc(time.Second*10,func(){
//向p进程发送退出信号
p.Signal(os.Kill)
})
//等待进程p的退出,返回进程状态
ps,_ := p.Wait()
fmt.Println(ps.String())
// 获得所有环境变量
s := os.Environ()
fmt.Printf("s: %v\n", s)
// 获某个环境变量
s2 := os.Getenv("GOPATH")
fmt.Printf("s2: %v\n", s2)
// 设置环境变量
os.Setenv("env1","env1")
s2 = os.Getenv("aaa")
fmt.Printf("s2: %v\n", s2)
// 查找
s3,b := os.LookupEnv("env1")
fmt.Printf("b: %v\n", b)
fmt.Printf("s3: %v\n", s3)
// 替换
os.Setenv("NAME","gopher")
os.Setenv("BURROW","/usr/gopher")
fmt.Println(os.ExpandEnv("$NAME lives in ${BURROW},"))
// 清空环境变量
// os.Clearenv()
Input Output
IO操作封装如下几个包:
* io为IO原语(I/O primitives)提供基本的接口
* io/ioutil封装一些试用的I/O函数
* fmt实现格式化I/O,类似C语言中的printf和scanf
* bufio实现带缓冲I/O
io接口:Reader和Writer接口
Reader接口:
type Reader interface{
Read(p []byte) (n int,err error)
}
Writer接口:
type Writer interface{
Write(p []byte) (n int,err error)
}
哪些类型实现Reader和Writer接口
* os.File同时实现了io.Reader和io.Writer
* strings.Reader实现了io.Reader
* bufio.Reader/Writer分别实现io.Reader和io.Writer
* bytes.Buffer同时实现
* bytes.Reader实现io.Reader
* compress/gzip.Reader/Writer分别实现
* crypto/cipher.StreamReader/StreamWriter分别实现
* crypto/tls.Conn同时实现
* encoding/csv.Reader/Writer分别实现
io/ioutil:封装一些实用的I/O函数
ReadALL:读取数据,返回读到的字节slice
ReadDir:读取一个目录,返回目录入口数组[]os.FileInfo
ReadFile:读一个文件,返回文件内容(字节slice)
WriteFile:根据文件路径,写入字节slice
TempDir:在一个目录中创建指定前缀名的临时目录,返回新临时目录的路径
TempFile:在一个目录创建指定前缀名的临时问价,返回os.File
实例:
func readall(){ // 读文件
// r := strings.NewReader("hello world!")
f,_ := os.Open("a.txt") //File实现了Reader接口
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil{
fmt.Printf("err: %v\n", err)
}
fmt.Printf("b: %v\n", string(b))
}
func testReadDir(){ // 读目录
fi, _ := ioutil.ReadDir(".")
for _, v := range fi{
fmt.Printf("v: %v\n", v.Name())
}
}
func testReadFile(){ // 读文件
b,_ := ioutil.ReadFile("a.txt")
fmt.Printf("string(b): %v\n", string(b))
}
func testWriteFile(){ // 写文件
ioutil.WriteFile("a.txt",[]byte("hello world"),0664) // 0664 给权限,将hello world写入a.txt
}
func testTempFile(){ // 创建临时文件,会在Temp目录下临时创建文件
content := []byte("temporary file's content")
tmpfile,err := ioutil.TempFile("","example")
if err != nil{
log.Fatal(err)
}
fmt.Printf("tmpfile.Name(): %v\n", tmpfile.Name())
if _, err := tmpfile.Write(content); err != nil{
log.Fatal(err)
}
if err := tmpfile.Close(); err != nil{
log.Fatal(err)
}
}
bufio:实现缓冲I/O,包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数对象。
实例一:
r := strings.NewReader("hello world")
r2 := bufio.NewReader(r) //通过bufio.NewReader封装一个Newreader
s,_ := r2.ReadString('\n')
fmt.Printf("s: %v\n", s)
实例二:func (*Reader)Read
s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWSYZ1234567890")
br := bufio.NewReader(s)
p := make([]byte,10)
for {
n,err := br.Read(p)
if err == io.EOF{
break
}else{
fmt.Printf("string(p):%v\n",string(p[0:n]))
}
}
示例三:
func(*Reader)ReadByte:
func (b *Reader) ReadByte()(c byte,err error): ReadByte读取并返回一个字节。如果没有可用数据会返回错误。
func(*Reader)UnreadByte:
func (b *Reader) UnreadByte() error: UnreadByte吐出最近一次读取操作读取的最后一个字节并且只能吐出最后一个。
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
c,_ := br.ReadByte()
fmt.Printf("c: %v\n", c)
c,_ = br.ReadByte()
fmt.Printf("c: %v\n", c)
br.UnreadByte()
c,_ = br.ReadByte()
fmt.Printf("c: %v\n", c)
实例四:
func (b *Reader)ReadRune():readRune读取一个utf-8编码的unicode码值,返回该码值,其编码长度和可能的错误。如果utf-8编码非法,读取位置只移动1字节,返回U+FFFD,返回值size为1而err为nil,如果没有可用数据会返回错误。
语法:func (b *Reader) ReadRune()(r rune, size int,err error)
func (b *Reader)UnreadRune():UnreadRune吐出最近一次ReadRune调用读取的unicode码值,如果最近一次读取不是调用的ReadRune,会返回错误。
语法:func (b *Reader) UnreadRune() error
s := strings.NewReader("hello world")
br := bufio.NewReader(s)
c,size,_ := br.ReadRune()
fmt.Printf("%c %v\n",c,size)
c,size,_ = br.ReadRune()
fmt.Printf("%c %v\n",c,size)
br.UnreadRune()
c,size,_ = br.ReadRune()
fmt.Printf("%c %v\n",c,size)
示例五:
func(*Reader)ReadLine:如果一行特别多,超过缓冲区大小,会把后面省略掉
语法:func (b *Reader) ReadLine()(line []byte,isPrefix bool,err error)
s := strings.NewReader("abc\NdEF\r\nGHI\r\nGHI")
br := bufio.NewReader(s)
w,isPrefix,_ := br.ReadLine()
fmt.Printf("%q %v\n",w,isPrefix)
w,isPrefix,_ = br.ReadLine()
fmt.Printf("%q %v\n",w,isPrefix)
w,isPrefix,_ = br.ReadLine()
fmt.Printf("%q %v\n",w,isPrefix)
w,isPrefix,_ = br.ReadLine()
fmt.Printf("%q %v\n",w,isPrefix)
实例六:
func (*Reader)ReadSlice:读取一个切片
语法:func (b *Reader) ReadSlice(delim byte)(line []byte,err error)
s := strings.NewReader("ABC,DEF,GHI,JKL")
br := bufio.NewReader(s)
w,_ := br.ReadSlice(',')
fmt.Printf("%q\n",w)
w,_ = br.ReadSlice(',')
fmt.Printf("%q\n",w)
w,_ = br.ReadSlice(',')
fmt.Printf("%q\n",w)
实例七:
func (*Reader) ReadString:读取一个字符串
func (b *Reader) ReadString(delim byte)(line string,err error)
s := strings.NewReader("ABC DEF GHI JKL")
br := bufio.NewReader(s)
w,_ := br.ReadString('')
fmt.Printf("%q\n",w)
w,_ = br.ReadString('')
fmt.Printf("%q\n",w)
w,_ = br.ReadString('')
fmt.Printf("%q\n",w)
实例八:
func (*Reader)WriteTo:WriteTo方法实现了io.WriterTo接口
func (b *Reader) WriteTo(w io.Writer)(n int64,err error)
s := strings.NewReader("ABCDEFGHIJKLMN")
br := bufio.NewReader(s)
b := bytes.NewBuffer(make([]byte,0))
br.WriteTo(b) // 写到缓冲区
fmt.Printf("%s\n",b)
type Writer:Writer实现了为io.Writer接口对象提供缓冲,如果在向一个Writer类型值写入时遇到了错误,该对象将不再接受任何数据,且所有写操作都会返回该错误。
实例:
type Writer struct{
err error
buf []byte
n int
wr io.Writer
}
func NewWriter: NewWriter创建一个具有默认大小缓冲、写入w的*Writer。NewWriter相当于NewWriterSize(wr,4096)
func NewWriter(w io.Writer) *Writer
func NewWriterSize: 创建一个具有最少有size尺寸的缓冲、写入w的Writer。如果参数w已经是一个具有足够大缓冲的Writer类型值,会返回w。
func NewWriter(w io.Writer,size int) *Writer
func (*Writer)Reset: Reset丢弃缓冲中的数据,清除任何错误,将b重设为将其输出写入w
func (b *Writer) Reset(w io.Writer)
f,_ := os.OpenFile("a.txt",os.O_RDWR,0777)
defer f.Close()
w := bufio.NewWriter(f) // 即可以writer也可以reader
w.WriteString("hello world!")
w.Flush() // 刷新缓冲区
func (b *Write)Bufferd() int: Buffered返回缓冲中已使用的字节数
b := bytes.NewBuffer(make([]byte,0))
bw := bufio.NewWriter(b)
bw.WriteString("123456789")
c := bytes.NewBuffer(make([]byte,0))
bw.Reset(c)
bw.WriteString("456")
bw.Flush()
fmt.Printf("b: %v\n", b)
fmt.Printf("c: %v\n", c)
func (b *Writer)Available() int: Available返回缓冲中还有多少字节未使用
func (b *Writer)Write(p []byte)(nn int,err error): 将p内容写入缓冲区,返回写入的字节数。如果返回值nn<len(p),会返回错误。
func (b *Writer)WriteString(s string)(int,error):写入字符串,返回字节数。
func (b *Writer)WriteByte(c byte)error:WriteByte写入单个字节
func (b *Writer)WriteRune(r rune)(size int,err error):写入一个unicode码值(utf-8编码),返回写入的字节数和可能的错误。
func (b *Writer)Flush()error:Flush方法将缓冲中的数据写入下层io.Writer接口
func (b *Writer)ReadForm(r io.Reader)(n int64,err error):ReadFrom实现io.ReaderFrom接口
b := bytes.NewBuffer(make([]byte,0))
bw := bufio.NewWriter(b)
fmt.Println(bw.Available()) //4096
fmt.Println(bw.Buffered()) // 0
bw.WriteString("abcdefghijklmn")
fmt.Println(bw.Available())
fmt.Println(bw.Buffered())
bw.Flush() // 刷新缓冲区
fmt.Println(bw.Available())
fmt.Printf("%q\n",b)
type ReadWriter struct{ // ReadWriter类型保管了指向Reader和Writer类型的指针,实现了io.ReadWriter接口
*Reader
*Writer
}
func NewReadWriter(r *Reader,W *Writer)*ReadWriter:申请创建一个新的、将读写操作分派给r和w的ReadWriter
b := bytes.NewBuffer(make([]byte,0))
bw := bufio.NewWriter(b)
s := strings.NewReader("123")
br := bufio.NewReader(s)
rw := bufio.NewReadWriter(br,bw)
p,_ := rw.ReadString('\n')
fmt.Println(string(p))
rw.WriteString("asdf")
rw.Flush()
fmt.Println(b)
Scanner类型是提供方便的读取数据接口。
type SplitFunc func(data []byte,atEOF bool)(advance int, token []byte,err error):SplitFunc类型代表用于输出作词法分析的分割函数
func ScanBytes(data []byte,atEOF bool)(advance int,token []byte,err error):ScanBytes是用于Scanner类型的分割函数(符合SplitFunc),本函数会将每个字节作为一个token返回。
func ScanRunes(data []byte,atEOF bool)(advance int,token []byte,err error):本函数将每个utf-8编码的unicode码值作为一个token返回,本函数返回的rune序列和range一个字符串的的输出rune序列相同。
func ScanWords(data []byte,atEOF bool)(advance int,token []byte,err error):会将空白分割片段作为一个token返回。
func ScanLines(data []byte,atEOF bool)(advance int,token []byte,err error):用于scanner类型的分割函数。
type Scanner struct{
r io.Reader
split SplitFunc
maxTokenSize int
token []byte
buf []byte
start int
end int
err error
}
func NewScanner(r io.Reader) *Scanner: NewScanner创建并返回一个从r读取数据的Scanner。
func (s *Scanner) Split(split SplitFunc):Split设置该Scanner的分割函数,本方法必须在scan之前调用。
s := strings.NewReader("ABC DEF GHI JKL")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan(){
fmt.Println(bs.Text())
}
func (s *Scanner) Scan() bool:获取当前位置token,并让Scanner的扫描位置移动到下一个token.
s := strings.NewReader("hello world!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanBytes)
for bs.Scan(){
fmt.Printf("%s",bs.Text())
}
func (s *Scanner) Bytes()[]byte:返回最近一次Scan调用生成的token。底层数组指向的数据可能会被下一次Scan的调用重写。
s := strings.NewReader("hello world!")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanRunes)
for bs.Scan(){
fmt.Printf("%s",bs.Text())
}
func (s *Scanner) Text() string:bytes方法返回最近一次Scan带哦用生成的token,会申请创建一个字符串保存token并返回该字符串。
func (s *Scanner) Err() error:返回Scanner遇到的第一个EOF的错误。
log简介:内置的Log包简单实现日志服务,通过调用Log包函数可实现日志打印功能
使用:Log包内有3个系列日志打印函数,print系列、panic系列、fatal系列
print:单纯打印日志
panic:打印日志抛出panic异常
fatal:打印日志,强制结束程序(os.Exit(1),defer函数不会执行)
实例:
log.Print("my log")
log.Printf("my log %d",100)
name := "tom"
age := 20
log.Println(name," ",age)
默认情况下log指挥打印出时间,但是实际情况下我们可能还需要获取文件名,行号等信息,log包提供给我们定制的接口。
log包提供两个标准Log配置的相关方法:
func Flags() int // 返回标准log输出配置
func SetFlags(flag int) // 设置标准log输出配置
flag参数:
const{
//控制输出日志信息的细节,不饿能控制输出的顺序和格式
//输出的额日志在每一项后会有一个冒号分隔,例如2009/1/1 0101:01 123123 /a/b/c.go:23:message
Ldate = 1 << iota //日期
Ltime //时间
Lmicroseconds //微妙级别的时间
Llongfile //文件全路径名+行号
Lshorfile //文件名+行号
LUTC //使用UTC时间
LstdFlags = Ldate | Ltime //标准logger的初始值
}
示例:
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
i := log.Flags()
fmt.Printf("i:%v\n",i)
log.Print("my log...")
日志前缀配置:
log包提供两个日志前缀配置的相关函数:
func Prefix() string //返回日志的前缀配置
func SetPrefix(prefix string) //设置日志前缀
示例:
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.SetPrefix("MyLog:")
f,err := os.OpenFile("a.log",os.O_WRONLY|os.O_APPEND|os.O_CREATE,0664)
if err != nil{
log.Fatal("日志文件错误")
}
log.SetOutput(f)
自定义logger:
log包中提供了func New(out io.Writer,prefix string,flag int) *Logger函数来实现自定义logger
示例:
var logger *log.Logger
func init(){
logFile,err := os.OpenFile("a.log",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0644)
if err != nil{
log.Panic("打开日志文件异常")
}
logger = log.New(logFile,"success",log.Ldate|log.Ltime|log.Lshortfile)
logger.Println("自定义Logger")
}
builtin包提供了类型声明、变量、常量声明,还有一些便利函数,这个包不需要导入,可以直接使用。
常用函数:
append: 切片
func append(slice []Type,elems ...Type)[]Type
slice = append(slice,elem1,elem2) //直接在slice后面添加单个元素,添加元素类型可以和slice相同,也可以不同
slice = append(slice,anotherSlice...) //直接将另一个slice添加到slice后面,但其本质还是将anotherSlice中的元素一个一个添加到slice中,和第一种方法类似
示例:
s1 := []int{1,2,3}
i := append(s1,4)
fmt.Printf("i:%v\n",i)
s2 := []int{7,8,9}
i2 := append(s1,s2...)
fmt.Printf("i2: %v\n", i2)
len: 返回、数组、切片、字符串、通道的长度
示例:
s1 := "hello world"
i := len(s1)
fmt.Printf("i: %v\n", i)
s2 := []int{1,2,3}
fmt.Printf("s2: %v\n", len(s2))
Print、Println: 打印输出到控制台
示例:
name := "tom"
age := 20
print(name," ",age,"\n")
println(name," ",age)
panic: 抛出一个panic异常
示例:
defer fmt.Println("panic 异常后执行")
panic("panic 错误...")
fmt.Println("end...")
new和Make:
1.make只能用来分配及初始化类型为slice,map,chan的数据;new可以分配任意类型的数据
2.new分配返回的是指针,即类型*T;make返回引用,即T;
3.new分配的空间被清零,make分配后,会进行初始化
示例:
NEW:
b := new(bool)
fmt.Printf("b: %v\n", *b)
i := new(int)
fmt.Printf("i: %v\n", *i)
s := new(string)
fmt.Printf("s: %v\n", *s)
MAKE:
make([]int,10,100)
bytes包提供了对字节切片进行读写操作的一系列函数,字节切片处理的函数比较多分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。
// Contains : 字符串强转为byte切片
s := "cllmsy.com"
b := []byte(s) // 强类型转换
b1 := []byte("cllmsy.com")
b2 := []byte("cllmsy.cn")
b3 := bytes.Contains(b,b1)
fmt.Printf("%v",b3)
b3 = bytes.Contains(b,b2)
fmt.Printf("b3:%v\n",b3)
strings.Contains("hello world","hello") // 判断是否含有hello
// Count
s := []byte("helloooooo")
sep1 := []byte("h")
sep2 := []byte("l")
sep3 := []byte("o")
fmt.Println(bytes.Count(s,sep1)) //1
fmt.Println(bytes.Count(s,sep2)) //2
fmt.Println(bytes.Count(s,sep3)) //9
// Repeat 重复
b = []byte("hi")
fmt.Println(string(bytes.Repeat(b,1))) //hi
fmt.Println(string(bytes.Repeat(b,3))) //hihihi
// Replace 替换
s := []byte("hello,world")
old := []byte("o")
news := []byte("ee")
fmt.Println(string(bytes.Replace(s,old,news,0))) //hello,world
fmt.Println(string(bytes.Replace(s,old,news,1))) //hellee,world
fmt.Println(string(bytes.Replace(s,old,news,2))) //hellee,weerld
fmt.Println(string(bytes.Replace(s,old,news,-1))) //hellee,weerld
// Runes
s := []byte("hello world")
r := bytes.Runes(s)
fmt.Printf("转换前字符长度: %v\n", len(s))
fmt.Printf("转换后字符长度: %v\n", len(r))
// Join
s2 := [][]byte{[]byte("hello"),[]byte("world")}
sep4 := []byte(",")
fmt.Println(string(bytes.Join(s2,sep4))) //hello,world
sep5 := []byte("#")
fmt.Println(string(bytes.Join(s2,sep5))) //hello#world
io.Reader实现了 io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScanner, io.RuneScanner接口,Reader是只读,可以seek。
示例:
data := "123456789"
re := bytes.NewReader([]byte(data)) //通过[]byte创建reader
fmt.Println("re len:",re.Len()) //返回未读取部分的长度
fmt.Println("re size:",re.Size()) //返回底层数据总长度
buf := make([]byte,2)
for {
n, err := re.Read(buf) //读取数据
if err != nil{
break
}
fmt.Println(stirng(buf[:n]))
}
re.Seek(0,0) //设置偏移量,因为上面的操作以及修改了读取位置等信息
for {
b ,err := re.ReadByte() //一个字节一个字节的读
if err != nil{
break
}
fmt.Println(string(b))
}
re.Seek(0,0)
off := int64(0)
for {
n,err := re.ReadAt(buf,off) //指定偏移量读取
if err!= nil{
break
}
off += int64(n)
fmt.Println(off,string(buf[:n]))
}
缓冲区是具有读取和写入方法的可变大小的字节缓冲区,buffer的零值是准备使用的空缓冲区
声明一个Buffer的四种方法:
var b bytes.Buffer //直接定义一个buffer变量,不用初始化,直接使用
b := new(bytes.Buffer) //使用new返回buffer变量
b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个buffer
b := bytes.NewBufferString(s string) //从一个string变量,构造一个buffer
示例:
var b bytes.Buffer
fmt.Printf("b: %v\n", b)
var b1 = bytes.NewBufferString("hello")
fmt.Printf("b1: %v\n", b1)
var b2 = bytes.NewBuffer([]byte("hello"))
fmt.Printf("b2: %v\n", b2)
往buffer中写入数据:
b.Write(d []byte) //将切片d写入buffer尾部
b.WriteString(s string) //将字符串s写入buffer尾部
b.WriteByte(c byte) //将字符c写入Buffer尾部
b.WriteRune(r rune) //将一个rune类型的数据放到缓冲器的尾部
b.WriteTo(w io.Writer) //将buffer中的内容输出到实现了io.Writer接口的可写入对象中
示例:
var b bytes.Buffer
n,_ := b.WriteString("hello")
fmt.Printf("b: %v\n", b.Bytes())
fmt.Printf("n: %v\n", n)
errors实现了操作错误的函数。语言使用error类型来返回函数执行过程中遇到的错误,如果返回的error值为nil,则表示未遇到错误,否则error会返回一个字符串,说明有问题。
结构:
type error interface{
Error() string
}
1.可以用任何类型实现它,只要添加一个Error()方法接口。
2.error不一定表示一个错误,它可以表示任何信息,比如Io包中就用error类型的io.EOF表示数据读取结束,而不是遇到了什么错误
3.errors实现了最简单的error类型,只包含一个字符串,就可以记录大多数情况下遇到的错误信息。
4.基本语法:func New(text string) error
示例:
func check(s string)(string,error){
if s == ""{
err := errors.New("字符串不能为空")
return "",err
}else{
return s, nil
}
}
自定义错误:
import (
"fmt"
"time"
)
type MyError struct{
When time.Time
What string
}
func (e MyError) Error() string{
return fmt.Sprintf("%v:%v",e.When,e.What)
}
func oops() error{
return MyError{
time.Date(1989,3,15,22,30,0,0,time.UTC),
"the file system has go ne away",
}
}
func main() {
if err := oops(); err!= nil{
fmt.Println(err)
}
}
sort包提供了排序切片和用户自定义数据集以及相关功能的函数
sort包主要针对[]int、[]float64、[]string以及其它自定义切片的排序
结构体:
type IntSlice struct
type Float64Slice
type StringSlice
函数:
func Ints(a []int)
func IntsAreSorted(a []int) bool
func SearchInts(a []int, x int) int
func Float64s(a []float64)
func Float64sAreSorted(a []float64) bool
func SearchFloat64s(a []float64,x float64) int
func SearchFloat64s(a []float64,x float64) bool
func Strings(a []string)
func StringsAreSorted(a []string)bool
func SearchStrings(a []string) bool
func Sort(data Interface)
func Stable(data Interface)
func Reverse(data Interface) Interface
func ISSorted(data Interface) bool
func Search(n int,f func(int) bool) int
示例:
s := []int{2,4,1,3}
sort.Ints(s)
fmt.Printf("s:%v\n",s)
接口type Interface:
type Interface interface{
Len() int //Len方法返回集合中的元素个数
Less(i,j int) bool //i>j,该方法返回索引i的元素是否比索引j的元素小
Swap(i,j int) //交换i,j的值
}
示例:
type NewInts []uint
func (n NewInts) Len() int{
return len(n)
}
func (n NewInts) Less(i,j int) bool{
fmt.Println(i,j,n[i] < n[j],n)
return n[i] < n[j]
}
func (n NewInts) Swap(i,j int){
n[i],n[j] = n[j],n[i]
}
func main() {
n := []uint{1,3,2}
sort.Sort(NewInts(n))
fmt.Println(n)
}
结构体:
func (p xxxSlice) Len() int //切片长度
func (p xxxSlice) Less(i,j int) bool
func (p xxxSlice) Swap(i,j int)
func (p xxxSlice) Search(x xxx) int
//这个和后面功能一致
func (p xxxSlice) Sort()
综合实例:
[]float64:
f := []float64{1.1,4.4,5.5,3.3,2.2}
sort.Float64s(f)
fmt.Printf("f:%v\n",f)
[]int:
f := []int{3,5,1,2,4}
sort.Ints(f)
fmt.Printf("f:%v\n",f)
[]string:
//字符串排序,先比较高位,相同再比较低位
ls := sort.StringSlice{
"100",
"42",
"41",
"3",
"2",
}
fmt.Println(ls)
sort.Strings(ls)
fmt.Println(ls)
[][]int: // 复杂结构
type testSlice [][]int
func(l testSlice) Len() int {return len(1)}
func(l testSlice) Swap(i,j int) {l[i],l[j]=l[j],l[i]}
func(l testSlice) Less(i,j int) bool {return l[i][1]<l[j][1]}
func main(){
ls := testSlice{
{1,4},
{9,3},
{7,5},
}
fmt.Println(ls)
sort.Sort(ls)
fmt.Println(ls)
}
[]map[string]int [{"k:0"},{"k1":1},{"k2",2]}]: // 复杂结构体
type testSlice []map[string]float64
func (l testSlice) Len() int {return len(1)}
func (l testSlice) Swap(i,j int) {l[i],l[j]=l[j],l[i]}
func (l testSlice) Less(i,j int) bool {return l[i]["a"] < l[j]["a"]} //按照a对应的值排序
func main{
ls := testSlice{
{"a":4,"b":12},
{"a":3,"b":11},
{"a":5,"b":10},
}
fmt.Println(ls) //[map[a:4 b:12] map[a:3 b:11] map[a:5 b:10]]
sort.Sort(ls)
fmt.Println(ls) //[map[a:3 b:11] map[a:4 b:12] map[a:5 b:10]]
}
[]struct://复杂结构体
type People struct{
Name string
Age int
}
type testSlice []People
func(l testSlice) Len() int {return len(l)}
func(l testSlice) Swap(i,j int) {l[i],l[j]=l[j],l[i]}
func(l testSlice) Less(i,j int) {return l[i].Age < l[j].Age}
func main(){
ls := testSlice{
{Name:"n1",Age:12},
{Name:"n2",Age:11},
{Name:"n3",Age:10},
}
fmt.Println(ls)
sort.Sort(ls)
fmt.Println(ls)
}
time包提供测量和显示时间的功能。
基本使用示例:
func test1(){
now := time.Now() //获取当前时间
fmt.Printf("current time:%v\n",now)
year := now.Year()
month := now.Year()
day := now.Day()
hour := now.Hour()
minute := now.Minute()
second := now.Second()
fmt.Printf("%d,%02d %02d:%02d %02d\n",year,month,day,hour,minute,second)
}
时间戳:时间戳是指某个时间段至当前时间的总毫秒数,被称为Unix时间戳(例如用在web开发中cookies有效期,接口加密,Redis中Key有效期等)
示例一:Unix()
func test2(){
now := time.Now()
fmt.Printf("%T,%v",now.Unix(),now,Unix())
}
示例二:time.UnixNow(),time.UnixNano()
func test3(){
now := time.Now()
fmt.Printf("%T,%v\n",now.UnixNano(),now.UnixNano())
}
时间戳转化为普通的时间格式:time.Unix
func timeStampToTime(){
timestamp := time.Now().Unix()
timeObj := time.Unix(timestamp,0) //将时间戳转为时间格式
fmt.Println(timeObj)
year := timeObj.Year() // 年
month := timeObj.Month() //月
day := timeObj.Day() //日
hour := time.Obj.Hour() //小时
minute := timeObj.Minute() //分钟
second := timeObj.Second() //秒
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n",year,month,day,hour,minute,second)
}
操作时间:ADD
func add(h,m,s,mls,msc,ns time.Duration){
now := time.Now()
fmt.Println(now.Add(time.Hour*h + time.Minute*m + time.Second*s + time.Millisecond*mls + time.Microsecond*msc + time.Nanosecond*ns))
}
func main(){
test4(3,4,5,6,7,8)
}
定时器:time.Tick(时间间隔)
func tick(){
ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
for i := range ticker{
fmt.Println(i) //每秒执行任务
}
}
时间格式化:Format
func format(){
now := time.Now()
//24小时制
fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
//12小时制
fmt.Println(now.Foramt("2006-01-02 03:04:05.000 PM Mon Jan"))
}
解析字符串格式的时间:
now := time.Now()
fmt.Println(now)
//加载时区
loc,err := time.LoadLocation("Asia/Shanghai")
if err != nil{
fmt.Println(err)
return
}
//按照指定时区和指定格式解析字符串时间
timeObj,err := time.ParseInlocation("2006/01/02 15:00:00","2023/01/01 14:15:00",loc)
if err != nil{
fmt.Println(err)
return
}
fmt.Println(timeObj)
fmt.Println(timeObj.Sub(now))
实现Json编码和解码,将json字符串转换为struct,或者将struct转换为json
核心函数:
func Marshal(v interface{})([]byte,error):将struct编码成json,可以接受任意类型。
func Unmarshal(data []byte,v interface{}) error:将json转码为struct结构体。
核心结构体:
type Decoder struct{ //从输入流读取并解析json
// contains filtered or unexported fields
}
type Encoder struct{ //写json到输出流
// contains filtered or unexported fields
}
示例一:结构体转换为json
type Person struct{
Name string
Age int
Email string
}
func Marshl(){
p := Person{
Name: "tom",
Age: 20,
Email: "[email protected]",
}
b,_ := json.Marshal(p)
fmt.Printf("b:%v\n",string(b))
}
示例二:json转换为结构体
func Unmarshal(){
b1 := []byte(`{"Name":"tom","Age":20,"Email":"[email protected]"`)
var m Person
json.Unmarshal(b1,&m)
fmt.Printf("m:%v\n",m)
}
示例三:解析嵌套类型
func test3(){
b := []byte(`{"Name":"tom","Age":20,"Email":"[email protected]","Parents":["tom","kite"]}`)
var f interface{}
json.Unmarshal(b,%f)
fmt.Printf("f:%v\n",f)
}
示例四:解析嵌套引用类型
func test4(){
type Person struct{
Name string
Age int
Email string
Parent []string
}
p := Person{
Name: "tom",
Age : 20,
Email : "[email protected]",
Parent : []string{"big tom","big kite"},
}
b,_ := json.Marshal(p)
fmt.Printf("b:%v\n",string(b))
}
示例五:io流Reader Writer可以扩展到http websocket等场景
func test5(){
//dec := json.NewDecoder(os.Stdin)
//a.json : {"Nmae":"tom","Age":20,"Email":"[email protected]","Parents":["tom","kite"]}
f,_ := os.Open("a.json")
dec := json.NewDecoder(f)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v);err != nil{
log.Println(err)
return
}
fmt.Printf("v:%v\n",v)
if err := enc.Encode(&v); err != nil{
log.Println(err)
}
}
}
}
xml包实现xml解析
核心函数:
func Marshal(v interface{})([]byte,error):将struct编码成xml,可以接受任意类型。
func Unmarshal(data []byte,v interface{})error:将xml转码成struct结构体
核心结构体:
type Decoder struct{}:从输入流读取并解析xml
type Encoder struct{}:写xml到输出流
示例一:结构体转换为xml
type Person struct{
XMLName xml.Nmae `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
func Marshal(){
p := Person{
Name: "tom",
Age: 20,
Email: "[email protected]",
}
b,_ := xml.MarshalIndent(P," "," ")
fmt.Println("b:%v\n",string(b))
}
示例二:读写文件
func read(){
/*
tom
20
[email protected]
*/
b,_ := ioutil.ReadFile("a.xml")
var p Person
xml.Unmarshal(b,&p)
fmt.Printf("p:%v\n",p)
}
func write(){
type Person struct{
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
p := person{
Name:"tom",
Age:20,
Email:"[email protected]",
}
f,_ := os.OpenFile("a.xml",os.O_WRONLY,0777)
defer f.Close()
e := xml.NewEncoder(f)
e.Encode(p)
}
包含一些常量和一些有用的数学计算函数,例如:三角函数、随机数、绝对值、平方根等。
常量:
fmt.Printf("float64的最大值是:%.f\n",math.MaxFloat64)
fmt.Printf("float64的最小值是;%.f\n",math.SmallestNonzeroFloat64)
fmt.Printf("float32的最大值是:%.f\n",math.MaxFloat32)
fmt.Printf("float32的最小值是:%.f\n",math.SmallestNonzeroFloat32)
fmt.Printf("Int8的最大值是:%d\n",math.MaxInt8)
fmt.Printf("Int8的最小值是:%d\n",math.MinInt8)
fmt.Printf("Uint8的最大值是:%d\n",math.MaxUint8)
fmt.Printf("Int16的最大值是:%d\n",math.MaxInt16)
fmt.Printf("Int16的最小值是:%d\n",math.MinInt16)
fmt.Printf("Uint16的最大值是 :%d\n",math.MaxUint16)
fmt.Printf("Int32的最大值是 ;%d\n",math.MaxInt32)
fmt.Printf("Int32的最小值是 :%d\n",math.MinInt32)
fmt.Printf("Uint32的最大值是:%d\n",math.MaxUint32)
fmt.Printf("Int64的最大值是:%d\n",math .MaxInt64
fmt.Printf("Int64的最小值是:%d\n",math.MinInt64)
fmt.Printf("圆周率默认为 :%.28Bf\n",math,Pi)