go的接口,并发和并行,协程,信道,缓冲处理,异常处理

//指针 结构体  方法

//1 指针:(地址)
	-什么类型的指针,就是在类型前加 *
	-取什么变量的地址,就是在变量前加 &
	-通过指针得到值(解引用),在变量前加*
	
	-当参数传递,修改会影响原来的值
	-一般情况下,引用不需要再去地址了,取地址一般取值类型的地址
//2 结构体
	-面向对象当中的类,只有属性 ,没有方法(一系列属性的集合)
		type Person struct{ 一堆属性}
	-使用结构体:a:=Person{} 按位置,按关键字传参
	-取值: . 取值
	-结构体是值类型,默认是是属性的默认值
	-匿名结构体
	-匿名字段
	-结构体嵌套(变量提升)
	-结构体比较(如果结构体中有引用类型,不支持比较)
//3 方法(特殊的函数)
	-func关键字和函数名之间有个特殊类型接收器
		-func (a 结构体名字)方法名(参数)(返回值){}
	-绑定给结构体,结构体通过 . 方式来调用
	-值接收器和指针接收器(值接收器不会修改原来的,指针接收器会修改原来的)
	-不论值还是指针,都可以直接调用方法(值接收器类型,指针接收器类型)
	-匿名字段的方法(方法提升,类似于面向对象中的继承,多继承)
	-非结构体上绑定方法(自己定义的属性)
	


//go的指针,结构体,匿名结构体,匿名字段,信道,缓冲信道,方法,函数,接口,goroutine,闭包函数,匿名函数

1 接口

//一系列方法的集合,规范了子类的行为,    
	-python和go都属于鸭子类型,非侵入式接口
	-java:侵入式接口
package main

import "fmt"

//1 定义一个接口,(规范行为,没有具体实现)
type DuckInterface interface {
	Run()
	Speak()
}

//定义一个TDuck结构体
type TDuck struct {
	name string
	age int
	wife string
}
//TDuck实现接口(实现接口中的所有方法)
func (t TDuck)Run()  {
	fmt.Println("我是唐老鸭,我的名字是",t.name,"我说人话")
}
func (t TDuck)Speak()  {
	fmt.Println("我是唐老鸭,我的名字是",t.name,"我学人走路")
}

//定义一个RDuck结构体
type RDuck struct {
	name string
	age int
}
//RDuck实现接口(实现接口中的所有方法)
func (t RDuck)Run()  {
	fmt.Println("我是普通肉鸭,我的名字是",t.name,"我阿嘎嘎叫")
}
func (t RDuck)Speak()  {
	fmt.Println("我是普通肉鸭,我的名字是",t.name,"我歪歪扭扭走路")
}


// 5 有名空接口
type EmptyInterface interface {

}

func main() {
	//2 实例化得到TDuck和RDuck两个对象
	//t:=TDuck{"鸡哥",88,"凤姐"}
	r:=RDuck{"普通鸭子",2}
	//t.Run()
	//t.Speak()
	//r.Run()
	//r.Speak()
	//接口也是一个类型(可以定义一个变量是接口类型)
	// 同一类事物的多种形态
	//var d DuckInterface
	//d=t
	////d=r
	//d.Speak()
	//d.Run()
	//想再去t的属性,name,age,wife
	//test(t)
	//test(r)


	// 5 空接口
	//-只要一个类型,实现接口所有的方法,就叫实现该接口
	//-如果一个接口是空的,一个方法都没有,所有类型都实现了空接口
	//-任意类型,都可以赋值给空接口类型
	//var a EmptyInterface
	//a=1
	//a="xx"
	//a=[3]int{1,2,3}

	//6 接口类型空值(nil)
	//var a EmptyInterface
	//fmt.Println(a)

	//7 匿名空接口
	// interface{}
	test(1)
	test(r)
	test(1.2)



}

////3 类型断言
//func test(d DuckInterface)  {
//	//d.Run()
//	//d.Speak()
//	//var t TDuck
//	//t=d.(TDuck)
//	t:=d.(TDuck) //断言d是TDuck类型,如果正确,就会把d转成t
//	fmt.Println(t.name)
//	fmt.Println(t.wife)
//	t.Speak()
//	t.Run()
//}

//4 类型选择
//func test(d DuckInterface)  {
//	switch a:=d.(type) {
//	case TDuck:
//		fmt.Println(a.wife)
//		fmt.Println("你是TDuck类型")
//	case RDuck:
//		fmt.Println(a.name)
//		fmt.Println("你是RDuck类型")
//	default:
//		fmt.Println("不知道是什么类型")
//	}
//}

//7 匿名空接口
//func test(i interface{})  {
func test(i EmptyInterface)  {
	fmt.Println(i)
}
	
package main

// 1 实现多个接口
//type DuckInterface1 interface {
//	Run()
//	Speak()
//}
//
//type HumanInterface interface {
//	Drive()
//}
//
////定义一个TDuck结构体
//type TDuck1 struct {
//	name string
//	age int
//	wife string
//}
////TDuck实现接口(实现接口中的所有方法)
//func (t TDuck1)Run()  {
//	fmt.Println("我是唐老鸭,我的名字是",t.name,"我说人话")
//}
//func (t TDuck1)Speak()  {
//	fmt.Println("我是唐老鸭,我的名字是",t.name,"我学人走路")
//}
////实现HumanInterface接口
//func (t TDuck1)Drive()  {
//	fmt.Println("我是唐老鸭,我开车")
//}

// 2 接口嵌套
type DuckInterface1 interface {
	Run()
	Speak()
}

type HumanInterface interface {
	DuckInterface1
	//相当于
	//Run()
	//Speak()
	Drive()
}

func main() {
	//t:=TDuck1{"鸡哥",18,"凤姐"}
	//var d DuckInterface1
	//var h HumanInterface
	//d=t
	//d.Run()
	//d.Speak()
	//h=t
	//h.Drive()

}

2 并发和并行

//并发:假如在他晨跑时,鞋带突然松了。于是他停下来,系一下鞋带,接下来继续跑
//并行:如这个人在慢跑时,还在用他的 iPod 听着音乐


3 go协程

//go协程--》goroutine,并不是真正的协程(线程+协程,语言层面处理了,不需要开发者去关注)

package main

import (
	"fmt"
	"time"
)

func hello()  {
	fmt.Println("go go go!")
}
func main() {
	fmt.Println("主函数开始")
	go hello() //通过go关键字,开启goroutine,并发执行
	go hello()
	go hello()
	go hello()

	fmt.Println("主函数结束")
	time.Sleep(2*time.Second)

}

4 信道

//goroutine直接通信
//go语言不推崇共享变量方法做通信,而推崇管道通信channel(信道)
// 信道(管道)
package main

import (
	"fmt"
	"time"
)

func main() {
	//1 信道也是一个变量(需要指明运输的类型)
	//var a chan int //定义一个int类型信道

	//2 信道的0值,nil类型,它是一个引用
	//fmt.Println(a)

	//3 信道初始化
	//var a chan int=make(chan int)
	//fmt.Println(a)

	//4 信道的放值,和取值
	//var a chan int=make(chan int)
	//a<-1   //放值,把1放到信道中
	////var b int=<-a    //取值
	//<-a    //取值

	//5 默认情况下,信道的放值和取值都是阻塞的(一次一个都放不进去)
	fmt.Println("开始")
	var a chan bool=make(chan bool)
	//信道是引用类型
	go hello1(a)

	<-a
	time.Sleep(2*time.Second)



}

func hello1(a chan bool)  {
	fmt.Println("go go go")
	a<-true
	fmt.Println("xxx")
}
//信道案例

package main
/*
输入 453  计算每一位的平方和和每一位的立方和的和
squares = (4 * 4) + (5 * 5) + (3 * 3)
cubes = (4 * 4 * 4) + (5 * 5 * 5) + (3 * 3 * 3)
output = squares + cubes
 */


import (
	"fmt"
)

func calcSquares(number int, squareop chan int) {
	sum := 0
	for number != 0 {
		digit := number % 10   //% 取余数 453对10取余数--》3--》5--》4
		sum += digit * digit
		number /= 10          // /除以  453除以10----》45--》5--》0
	}
	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 := 4535
	sqrch := make(chan int)
	cubech := make(chan int)
	go calcSquares(number, sqrch)
	go calcCubes(number, cubech)
	squares, cubes := <-sqrch, <-cubech
	//squares:= <-sqrch
	//cubes := <-cubech
	fmt.Println("Final output", squares + cubes)
}
package main

func main() {
	//1 死锁

	//var a chan int=make(chan int)
	//a<-1  //一直阻塞在这,报死锁错误
	//<-a     //一直阻塞在这,报死锁错误

	//2 单向信道(只写或者只读)
	//sendch := make(chan int) //定义一个可写可读信道
	//go sendData(sendch)
	//fmt.Println(<-sendch)  //只能往里写值,取值报错

	//3 信道的关闭 close
	//sendch := make(chan int)
	//close(sendch)

}
func sendData(sendch chan<- int) {  //转成只写信道
	sendch <- 10
	//<-sendch  //只要读就报错
}

package main

import (
	"fmt"
)

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 := range ch {  //如果信道没关闭,一直取值,直到没有值,会报死锁
		fmt.Println("Received ",v)
	}
}

5 缓冲信道

//有缓冲信道(信道可以放多个值)

package main

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

func main() {
	//1 有缓冲信道的定义和死锁问题
	//var a chan int =make(chan int,4)  //长度为4的有缓冲信道
	//a<-1
	//a<-2
	////a<-3
	////a<-4
	////管子满了
	////a<-5  //报死锁错误
	////推断出无缓冲信道 var a chan int =make(chan int,0)
	//fmt.Println(<-a)
	//fmt.Println(<-a)
	////管子没有东西了,再取,报死锁
	//fmt.Println(<-a)

	//2 信道的容量和长度
	//长度是目前管道中有几个值,容量是管道最多能容纳多少值
	//var a chan int =make(chan int,4)
	//fmt.Println(len(a))
	//fmt.Println(cap(a))
	//a<-1
	//a<-2
	//fmt.Println(len(a))
	//fmt.Println(cap(a))

	//3 小案例(通过信道实现goroutine的同步)
	//var a chan int =make(chan int,3)
	////b:=<-a
	//go test3(a)
	//
	//fmt.Println(<-a)
	//
	//fmt.Println(<-a)

	//4 通过waitgroup实现同步
		no := 3
		var wg sync.WaitGroup  //值类型,没有初始化,有默认值
		for i := 0; i < no; i++ {
			wg.Add(1)
			go process(i, &wg)
		}
		wg.Wait() //add了几次,必须有几个wg.Done()对应,否则一直等在这
		fmt.Println("All go routines finished executing")
}

func process(i int, wg *sync.WaitGroup) {
	fmt.Println("started Goroutine ", i)
	time.Sleep(2 * time.Second)
	fmt.Printf("Goroutine %d ended\n", i)
	wg.Done()
}



//func test3(a chan int)  {
//	a<-1
//
//	time.Sleep(time.Second*2)
//	fmt.Println("假设我在运算")
//
//	a<-2
//	close(a)
//
//}


6 异常处理

//异常处理
package main

import "fmt"

//func main() {
//	f1()
//	f2()
//	f3()
//}
//func f1()  {
//	fmt.Println("f1")
//}
//
//func f2()  {
//	fmt.Println("f2")
//	//如果这个地方出了异常
//}
//func f3()  {
//	fmt.Println("f3")
//}

//defer:延迟执行,即便程序出现严重错误,也会执行
//panic:主动抛出异常 raise
//recover:恢复程序,继续执行

//func main() {
//	//defer fmt.Println("我最后才执行")  //先注册,等函数执行完成后,逆序执行defer注册的代码
//	//defer fmt.Println("ddddd")
//	defer func() {
//		fmt.Println("我最后才执行")
//	}()
//	defer func() {
//		fmt.Println("我最后才执行")
//		//出异常
//		//这个代码执行不到了
//	}()
//
//	fmt.Println("111")
//	fmt.Println("222")
//	panic("我出错了")  //主动抛出异常
//	//var a []int =make([]int,2,3)
//	//fmt.Println(a[9])
//	fmt.Println("这句话还会执行吗 ?不会了")
//}

//在defer中恢复程序,继续执行
func main() {

	f1()
	f2()
	f3()
}
func f1()  {
	fmt.Println("f1")
}

func f2()  {
	defer func() {
		//recover() //恢复程序继续执行
		if err:=recover();err!=nil{  //err 如果不为nil(空),表示出了异常
			fmt.Println(err)  //把异常信息打印出来
		}

	}()
	fmt.Println("f2")
	//如果这个地方出了异常
	panic("我出错了")

	fmt.Println("永远执行不到")
}
func f3()  {
	fmt.Println("f3")
}

// python中
//print('ssss')
//try:
//	print('ssss')
//	raise("xxxx")
//	print('我永远不会执行')
//except Exception as e:
//	print(e)
//finally:
//	print('我永远会执行')

//go 中
//print('ssss')
//defer func() {
//	if err:=recover();err!=nil{
//		fmt.Println(err)
//	}
//	//finally 写在这
//	print('我永远会执行')
//}()
//print('ssss')
//panic("xxxx")
//print('我永远不会执行')

补充

1 进程,线程,协程

# python中为什么让你开进程,由于cpython解释器,有GIL锁,同一时刻,只能有一个线程执行
# 开进程--》相当于开了多个线程,重新起了一个cpython解释器,运行代码
posted @ 2020-05-08 11:08  alen_zhan  阅读(721)  评论(0编辑  收藏  举报
返回顶部