DAY 101 go05

 

 

1w字---》技能点,项目
自我介绍 5--6分钟(你的个人介绍,以及一个项目的详细介绍)
面试套路,不会的问题作何反应,面试最后的收尾

五险一金

 1 字符串

    -utf-8
   -字节长度(len),字符长度(utf8包下)
   -for循环迭代循环(字符),索引循环(字节)
   
2 指针
-& 放在变量前,表示取该变量的地址
   -* 放在变量前,表示解引用
   -* 放在类型前,表示指向这个类型的指针
   
   -零值:nil
   -向函数传递指针参数
  -(*a)
   -不支持指针运算
   
   -数组指针,指针数组
   
   
3 结构体:一系列属性(字段)的集合
-结构: type 名字 struct{
      属性1 类型
      属性2 类型
  }
  -匿名结构体:type 名字都省略
  -用在内部,只使用一次
  -结构体零值:值类型,当作参数传递,修改不会影响原来的
   -访问结构体字段:通过 .
   -导出字段:首字母是否是大写
   -结构体指针
   -匿名字段:字段没有名字,类型名就是字段名----》提升字段
   -结构体嵌套:结构体中套结构体(有名结构体,匿名结构体)
   -如果嵌套的结构体是匿名,这个结构体的字段会被提升:
   -结构体嵌套类似于---继承
   -结构体相等性:所有字段可比较,结构体才可以比较
   

1 方法

1 函数和方法
2 方法有特殊之处:绑定给谁,谁来调用,会把调用者自动传入

3 go中如何写方法
-方法其实就是一个函数,在 func 这个关键字和方法名中间加入了一个特殊的接收器类型。
   -接收器可以是结构体类型或者是非结构体类型。
   -接收器是可以在方法的内部访问的
package main

import "fmt"

// 方法

//type Address struct {
// province string
// city string
//}
//
//func (a Address)printAddr() {
// fmt.Println("省是:",a.province,"市是:",a.city)
//}
//
//type Person struct {
// name string
// age int
// Address // 匿名字段 结构体嵌套
//
//}
//// 方法,方法是绑定给Person这个结构体的
//// 值类型接收器
//func (p Person) changName(name string) {
// p.name=name
// fmt.Println(p)
//}
//func (p Person)printAddr() {
// p.Address.printAddr()
// fmt.Println("Person的省是:",p.Address.province,"市是:",p.Address.city)
//}
//// 指针类型接收器
//func (p *Person) changAge(age int) {
// p.age=age
//}
//
//// 普通函数
//func changName(p Person) {
// fmt.Println("名字被改了")
// fmt.Println(p)
//}


// 6 在方法中使用值接收器 与 在函数中使用值参数 在方法中使用指针接收器 与 在函数中使用指针参数
type Person struct {
name string
age int
}
//方法中使用值接收器
func (p Person)changeName(name string) {
p.name=name
}
// 在函数中使用值参数
func changeName(p Person,name string) {
p.name=name
}

//方法中使用指针收器
func (p *Person)changeAge(age int) {
p.age=age
}
// 在函数中使用指针
func changeAge(p *Person,age int) {
p.age=age
}




// 7 非结构体的方法(把原来的类型,重命名)
type MyInt int

func (i *MyInt)Add(){
(*i)++
}
func main() {
//1 方法的使用
//p:=Person{"lqz",19}
//p.changName() //自动传值

//2 为什么有了函数还用方法
//changName(p) // 调用函数
//p.changName() //调用方法


//3 指针接收器与值接收器
//p:=&Person{"lqz",19}
//p.changName("张三")
//fmt.Println(p)
//p.changAge(100)
//fmt.Println(p)


// 不管是值类型接收器还是指针类型接收器的方法,都可以使用值调用和指针调用
// 决定结构体对象是否能被修改,是接收器决定的,如果是值类型接收器,就不改,如果是指针类型接收器就修改原来的

//4 什么时候使用指针接收器,什么时候使用值接收器
// 当拷贝一个结构体的代价过于昂贵时

//5 匿名字段的方法(也会被提升)
//p:=Person{"lqz",19,Address{"山东","潍坊"}}
//p.printAddr()   // 匿名字段的方法也被提升
//p.Address.printAddr()

//6 不管是值类型接收器还是指针类型接收器的方法,都可以使用值调用和指针调用
//在方法中使用值接收器 与 在函数中使用值参数
// 在方法中使用指针接收器 与 在函数中使用指针参数
//p:=Person{"lqz",19}
////p:=&Person{"lqz",19}
////p.changeName("egon") // 方法:无论是值还是指针,都可以来调用
////fmt.Println(p)
////changeName(p,"egon") // 函数:类型严格,必须传值类型
//
//p.changeAge(99) // 方法:无论是值还是指针,都可以来调用
//changeAge(p,99) // 函数:类型严格,必须传指针类型


// 7 非结构体上的方法
var i MyInt=10
var i1 int =10
i.Add()
i.Add()
i.Add()
i.Add()
i.Add()
fmt.Println(i)
fmt.Println(i+MyInt(i1))  // 强类型,不同类型不能直接运算

}

 

2 接口

package main

import "fmt"

// 接口:接口定义一个对象的行为,   鸭子类型

/*
在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定。
在 Go 语言中,接口就是方法的集合。当一个类型实现了接口中的所有方法,我们称它实现了该接口
接口指定了一个类型应该具有的方法,并由该类型决定如何实现这些方法
*/

// 1 定义一个接口
type Duck interface {
speak()
run()
}

// 定义一个TDuck结构体
type TDuck struct {
name string
age int
wife string
}

// 定义一个普通鸭子结构体
type PDuck struct {
name string
age int
}

// 让TDuck实现Duck接口( 只要绑定接口中所有方法,就叫实现该接口)
func (t TDuck)speak() {
fmt.Printf("唐老鸭的名字是:%v,它说人话",t.name)
}
func (t TDuck)run() {
fmt.Printf("唐老鸭的名字是:%v,它是人走路",t.name)
}


// 让PDuck实现Duck接口( 只要绑定接口中所有方法,就叫实现该接口)
func (t PDuck)speak() {
fmt.Printf("普通的名字是:%v,它嘎嘎叫",t.name)
}
func (t PDuck)run() {
fmt.Printf("普通的名字是:%v,它走路歪歪妞妞",t.name)
}



// 定义一个空接口(所有类型都实现了空接口,空接口类型可以接收任意类型)
type Empty interface {
}


func main() {
// 1 接口的使用(接口也是一个类型)
//var duck Duck // 定义一个Duck接口类型的变量
//var tduck TDuck=TDuck{"egon",18,"迪丽热巴"}// 定义一个唐老鸭对象
//var pduck PDuck=PDuck{"鸭子1号",1} // 定义一个普通鸭子对象
//tduck.run()
//tduck.speak()

//pduck.run()
//pduck.speak()

//duck=tduck   //TDuck实现了Duck接口,就可以赋值给接口类型
//duck.run()   // duck接口类型具体类型TDuck的run方法   //
//duck.speak()


//2 不考虑具体类型的情况下使用变量
//var tduck TDuck=TDuck{"egon",18,"迪丽热巴"}
//run(tduck)
//var pduck PDuck=PDuck{"鸭子1号",1}
//run(pduck)


//3 类型断言(把接口类型,转成真正的具体类型)
//var tduck Duck=TDuck{"egon",18,"迪丽热巴"}
//test(tduck)

//var pduck PDuck=PDuck{"鸭子1号",1}
//test(pduck)

// 4 空接口 (没有任何方法的接口)
//var i Empty=10
//var i Empty="lqz"
//var i Empty=TDuck{"egon",19,"迪丽热巴"}
//fmt.Println(i)

//test2(10)

// 5 匿名空接口 (省略type和接口名)
//var i interface{}=88
//fmt.Println(i)

// 6 类型选择(使用switch,优雅的替换掉if-else)
//var i interface{}=88
//test3(i)
//test3("lqz")
test3(TDuck{"egon",19,"迪丽热巴"})


}

func run(d Duck) {
d.run()
}

func test(d Duck) {
// 断言出真正的类型(TDuck) v,ok:=变量.(类型)

if v,ok:=d.(TDuck);ok{
fmt.Printf(v.wife)
}else if v,ok:=d.(PDuck);ok{
fmt.Printf(v.name)
}


}

func test2(i Empty) {
fmt.Println(i)

}

func test3(i interface{}) {
switch v:=i.(type) {
case int:
fmt.Println("我是int")

case string:
fmt.Println("我是字符串")

case TDuck:
fmt.Println("我是唐老鸭类型")
//把唐老鸭的wife打印出来
fmt.Println(v.wife)

case PDuck:
fmt.Println("我是一个普通鸭子类型")

default:
fmt.Println("不知道什么类型")




}
}
package main

import "fmt"

// 接口其他:实现多个接口,接口嵌套,接口零值


// 1 实现多个接口

// 2 接口嵌套(继承)
type Duck1 interface {
speak()
run()
Animal  // 接口嵌套
}
//再定义一个Animal接口
type Animal interface {
eat()
}


// 定义一个TDuck1结构体,实现Duck1接口
type TDuck1 struct {
name string
age int
wife string
}


func (t TDuck1)speak() {
fmt.Printf("唐老鸭的名字是:%v,它说人话",t.name)
}
func (t TDuck1)run() {
fmt.Printf("唐老鸭的名字是:%v,它是人走路",t.name)
}


func (t TDuck1)eat() {
fmt.Printf("吃饭")
}

func main() {
// 1 实现多个接口
//var a Animal=TDuck1{"egon",19,"dlrb"}
//var b Duck1=TDuck1{"egon",19,"dlrb"}
//a.eat()
//b.speak()


// 2 接口嵌套
//var b Duck1=TDuck1{"egon",19,"dlrb"}

// 3 接口零值:nil,接口是引用类型
var b Duck1
fmt.Println(b)  //<nil> 接口是引用类型
}

 

3 go routine

package main

import (
"fmt"
"time"
)

//goroutine:go 协程
// 并发:在一个时间段内,执行多个任务
// 并行(多核支持):同一时刻,执行多个任务

/*
Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是轻量级线程。
与线程相比,创建一个 Go 协程的成本很小。因此在 Go 应用中,常常会看到有数以并千计的 Go 协程发地运行
*/


//开启协程:线程+协程的混合体(不会开启进程)


// 定义一个任务
func task() {
fmt.Println("go go go")
}
func task2() {
fmt.Println("go2 go2 go2")
}
func main() {
fmt.Println("开始了")
go task()  //并发了
//go task() //并发了
//go task() //并发了
go task2()  //并发了
time.Sleep(1*time.Second)
fmt.Println("结束了")

// 睡1s,gogogo 一定会打印出来

}

 

4 信道,缓冲信道

4.1 信道基础

package main

import (
"fmt"
"time"
)

// 信道:变量,不同go 协程之间通信的
//信道可以想像成 Go 协程之间通信的管道。如同管道中的水会从一端流到另一端,通过使用信道,数据也可以从一端发送,在另一端接收

func task3(c chan int) {

fmt.Println("go go go")
time.Sleep(1*time.Second)
c<-100  //往里放
//time.Sleep(1*time.Second)
fmt.Println("放完了")
}
func main() {
// 1 信道的定义和基本使用()
//var c chan int // 定义了一个int类型的信道
//var c chan int =make(chan int) // 定义并初始化
////往信道中放值
//c <-1   // 走到这一句,程序就卡住了
//// 从信道中取值
////<-c
//var a int = <-c
//fmt.Println(a)

// 信道是引用类型,零值为nil


// 2 发送与接收默认是阻塞的
//var c chan int =make(chan int)
//c <-1 //deadlock:死锁问题
//<-c     //deadlock:死锁


// 3 在一个goroutine中放值,另一个中取值
//var c chan int =make(chan int)
//go task3(c)
////var i int=<-c //往外取
//i:=<-c //往外取
//fmt.Println(i)
//fmt.Println("执行结束了?")









//2 借助信道,通道
//fmt.Println("开始了吗?")
//go task3()
//// task3协程执行完以后,再继续往下执行
//fmt.Println("结束了吗?")
}

4.2 信道操作

package main

// 4 信道的另一个例子: 通过并发计算一个数字的每一位:平方和+立方和
//func calcSquares(number int, squareop chan int) {
// sum := 0
// for number != 0 {
// digit := number % 10 // 589 % 20--->9
// sum += digit * digit // sum+=9*9
// number /= 10 // 58
// }
// squareop <- sum
//}
//
//func calcCubes(number int, cubeop chan int) {
// sum := 0
// for number != 0 {
// digit := number % 10
// sum += digit * digit * digit
// number /= 10
// }
// cubeop <- sum
//}
//
//func main() {
// number := 589
// sqrch := make(chan int)
// cubech := make(chan int)
// go calcSquares(number, sqrch)
// go calcCubes(number, cubech)
//
// squares, cubes := <-sqrch, <-cubech
// //cubes := <-cubech
// //squares := <-sqrch
// fmt.Println("Final output", squares+cubes)
//}



// 5 单向信道(了解)
//func sendData(sendch chan<- int) {
// //<-sendch
// sendch <- 10
//}

//func main() {
// sendch := make(chan int)
// go sendData(sendch)
// fmt.Println(<-sendch)
//}


// 6 信道的关闭
//func main() {
// var a chan int =make(chan int)
// //a<-1
// //close(a)
// //v,ok:=<-a
// //fmt.Println(v,ok)
//}

// 7 关闭信道的案例
func producer(chnl chan int) {
for i := 0; i < 10; i++ {
chnl <- i
}
close(chnl)
}
func main() {
ch := make(chan int)
go producer(ch)
//for {
// v, ok := <-ch
// if ok == false {
// break
// }
// fmt.Println("Received ", v, ok)
//}
//for v:=range ch{ // 通过range循环,如果信道没关闭,会一个个取值,如果信道关闭了,range之间结束
// fmt.Println("Received ", v)
//}
}

 

4.3 缓冲信道

package main

import (
"fmt"
)

// 缓冲信道
//func main() {
// 1 定义一个有缓冲信道,定义一个缓冲大小为1的信道
//var ch chan int=make(chan int,3)
//var ch chan int=make(chan int,0)
//ch<-1
//ch<-2
//ch<-3
//ch<-4
//fmt.Println(<-ch)
//fmt.Println(<-ch)
//fmt.Println(<-ch)

//fmt.Println(<-ch) // 死锁

// 2 信道的长度和容量:
//长度目前信道中有多少值,容量是该信道能缓冲多少值
// var ch chan int=make(chan int,3)
// ch<-1
// fmt.Println("长度是:",len(ch))
// fmt.Println("容量是:",cap(ch))
//
//}


func producer1(chnl chan int) {
for i := 0; i < 10; i++ {
chnl <- i

}
close(chnl)
}
func main() {
ch := make(chan int,3)
go producer1(ch)

for v:=range ch{ // 通过range循环,如果信道没关闭,会一个个取值,如果信道关闭了,range之间结束

fmt.Println("Received ", v)
}
}


 

4.4 waitgroup

package main

import (
"fmt"
"sync"
"time"
)

// 等待所有goroutine执行结束,主再执行
// WaitGroup 方案


func task5(i int,wg *sync.WaitGroup) {
fmt.Println("我是任务", i)
time.Sleep(1*time.Second)
wg.Done() //一个任务结束,就调用一次done
}

func main() {
var wg sync.WaitGroup // 值类型,不需要初始化,就有默认值
for i := 0; i < 5; i++ {
go task5(i,&wg)
wg.Add(1) // 开始一个任务,就调用add
}
wg.Wait()
fmt.Println("结束了")
}

 

5 select,mutex

package main

import (
"fmt"
"sync"
"time"
)

// go中不推崇使用共享变量来共享数据,并发安全问题, 需要加锁
// 推崇使用信道来共享数据
var x = 0
func increment(wg *sync.WaitGroup,lock *sync.Mutex) {
lock.Lock()
x = x + 1
time.Sleep(1*time.Millisecond)
lock.Unlock()

wg.Done()
}
func main() {
var w sync.WaitGroup
var lock sync.Mutex
for i := 0; i < 1000; i++ {
w.Add(1)
go increment(&w,&lock)

}
w.Wait()
fmt.Println("final value of x", x)
}
package main

import (
"fmt"
"time"
)

//select
//func server1(ch chan string) {
// time.Sleep(1 * time.Second)
// ch <- "from server1"
//}
//func server2(ch chan string) {
// time.Sleep(3 * time.Second)
// ch <- "from server2"
//
//}
//func main() {
// output1 := make(chan string)
// output2 := make(chan string)
// go server1(output1)
// go server2(output2)
// select { // 从多个信道中选择最快的执行
// case s1 := <-output1:
// fmt.Println(s1)
// case s2 := <-output2:
// fmt.Println(s2)
// }
//}

// 2 默认情况
//func process(ch chan string) {
// time.Sleep(10500 * time.Millisecond)
// ch <- "process successful"
//}
//
//func main() {
// ch := make(chan string)
// go process(ch)
// for {
// time.Sleep(1000 * time.Millisecond)
// select {
// case v := <-ch:
// fmt.Println("received value: ", v)
// return
// default:
// fmt.Println("no value received")
// }
// }
//
//}

// 3 死锁问题
//func main() {
// ch := make(chan string)
// select {
// case <-ch:
// }
//}


// 4 随机选取
func server1(ch chan string) {
ch <- "from server1"
}
func server2(ch chan string) {
ch <- "from server2"

}
func main() {
output1 := make(chan string)
output2 := make(chan string)
go server1(output1)
go server2(output2)
time.Sleep(1 * time.Second)
select {
case s1 := <-output1:
fmt.Println(s1)
case s2 := <-output2:
fmt.Println(s2)
}
}

 

6 异常处理

package main

import "fmt"

// 异常处理:try except finally

// panic,recover,defer

// defer:延迟执行,先注册,后执行(整个函数执行完了,再按defer的注册顺序,从下网上执行),即便程序出现了严重错误,defer也会执行
// panic: 就是python中的raise

// recover:恢复程序,继续执行
func main() {

//defer fmt.Println("我最后执行")
//defer fmt.Println("我倒数第二执行")
//defer func() {
// fmt.Println("我是一个匿名函数")
//}()
//fmt.Println("我先执行")

//fmt.Println("我执行了")
//panic("出错了")
//fmt.Println("永远不会执行")


//defer func() {
// //recover()
// fmt.Println("我恢复了")
//}()
//fmt.Println("我执行了")
//panic("出错了")
//fmt.Println("永远不会执行")



//f1()
//try:
// f2()
// f3()
//except Exception as e:
// print(e)


//f1()
//try:
// f2()
//except Exception as e:
// print(e)
// f3()

f1()

f2()

f3()

}

func f1() {
fmt.Println("我是f1")
}
func f2() {
defer func() {
if err:=recover();err!=nil{ // 如果不是nil表示有返回值,出异常了,处理异常
fmt.Println(err)
}
//fmt.Println("用永远会执行,我就是finally的代码")
}()
fmt.Println("我是f2")
panic("出错了我")
//var a []int=[]int{1,2,3}
//fmt.Println(a[99])
}
func f3() {
fmt.Println("我是f3")
}

其他


0 go操作mysql ,redis,es,kafka,rabbitmq
1 go 的web框架
-gin(类似于flask,借助于第三方,gorm框架),beego(类似于django:orm框架,缓存,信号。。。)

2 微服务
-go-zeor
   -go-micro
posted @ 2021-06-17 16:50  DEJAVU_ERIC  阅读(24)  评论(0编辑  收藏  举报