[14 Go语言基础-接口、go并发,信道,缓冲信道,锁,异常处理]

[14 Go语言基础-接口、go并发,信道,缓冲信道,锁,异常处理]

1 接口

# 在面向对象的领域里,接口一般这样定义:接口定义一个对象的行为。接口只指定了对象应该做什么,至于如何实现这个行为(即实现细节),则由对象本身去确定
# go 语言中,接口是一系列方法的集合

package main

import "fmt"

// 定义接口,go语言的接口,也是鸭子类型
// 侵入式接口和非侵入式接口
/*
type关键字  接口名字 interface{
	方法一
	方法二
}
 */

// 写一个鸭子接口,有run和speak方法
type Duck interface {
	//run(a int)(int)
	run()  // 没有具体实现
	speak()
}
// 定义一个普通鸭子结构体
type PDuck struct {
	name string
	age int
}
// 让PDuck结构体,实现Duck接口:绑定接口中的所有方法,这就叫实现该接口
func (self PDuck)run()  {
	fmt.Println("普通鸭子,走路歪歪妞妞")
}

func (self PDuck)speak()  {
	fmt.Println("普通鸭子,说话嘎嘎叫")
}



// 定义一个唐老鸭子结构体
type TDuck struct {
	name string
	age int
	wife string
}
// 让TDuck结构体,实现Duck接口:绑定接口中的所有方法,这就叫实现该接口
func (self TDuck)run()  {
	fmt.Println("唐老鸭,走路跟人一样")
}

func (self TDuck)speak()  {
	fmt.Println("唐老鸭,说人话")
}


// 定义一个空接口
type Empty interface {

}

type Hobby interface {
	printHobbyName()
}
type Person interface {
	eat(food string)
	Hobby
}

func (self TDuck)eat(food string)  {
	fmt.Println("唐老鸭",self.name,"吃了",food)
}
func main() {
	// 多态:同一类事物的多种形态
	// 多态性:不考虑对象具体类型的情况下使用对象
	//var pduck=PDuck{"肉鸭1号",1}
	//var tduck=TDuck{"唐老鸭1号",1,"刘亦菲"}
	//
	//var duck Duck
	//// 把同一种类型的对象,赋值给duck
	////duck=pduck
	//duck=tduck
	////fmt.Println(duck)
	//duck.run()

	// 函数的参数是接口类型(类型断言)
	//var pduck=PDuck{"肉鸭1号",1}
	////var tduck=TDuck{"唐老鸭1号",1,"刘亦菲"}
	//speak(pduck)

	// 空接口(没有任何方法的接口)
	// 所有类型都实现了空接口
	//var empty Empty
	//empty=1
	//empty="eee"
	//empty=[3]int{1,2,4}

	// 匿名空接口
	//test("dsdd")

	// 类型选择
	//var pduck=PDuck{"肉鸭1号",1}
	//var tduck=TDuck{"唐老鸭1号",1,"刘亦菲"}
	//var a int8
	//test2(a)


	// 实现多个接口
	//var p Person
	//var tduck =TDuck{}
	//p=tduck
	//p.eat("包子")
	//
	//var d Duck
	//d=tduck

	// 接口嵌套


	// 接口0值
	var p Person
	fmt.Println(p)   //<nil> 引用类型
	p.eat("ddd")




}

func speak(a Duck)  {
	//只要是实现了Duck接口的类型,都可以传入
	//a.speak()
	// 想看唐老鸭的wife属性
	// 类型断言(断言出具体的类型,再当该类型去使用)
	//v,ok:=a.(PDuck)
	//if ok{
	if v,ok:=a.(PDuck);ok{  //断言a是PDuck类型,如果断言成功,if条件,否则走else条件
		fmt.Println(v.name)

	}else if v1,ok1:=a.(TDuck);ok1{
		fmt.Println(v1.wife)
	}else  {
		fmt.Println("断言失败")
	}

}

func test(a interface{})  {
	fmt.Println(a)
}

func test2(a interface{})  {
	switch v:=a.(type) {   // 类型选择
	case PDuck:
		v.run()
		fmt.Println("普通鸭子")
	case TDuck:
		fmt.Println(v.wife)
		fmt.Println("唐老鸭")
	case int:

		fmt.Println("int 类型")
	case string:
		fmt.Println("字符串类型")
	default:
		fmt.Println("不知道什么类型")

	}
}


2 go并发

package main

import (
	"fmt"
	"time"
)

/*
并行是什么?并行和并发有何区别
并行是指同时处理多个任务(多个cpu支持)。这听起来和并发差不多,但其实完全不同。
假如这个人在慢跑时,还在用他的 iPod 听着音乐。这称之为并行
 */


//goroutine

func task()  {
	fmt.Println("go go go")
	time.Sleep(1*time.Second)
	fmt.Println("task结束")
}

func main() {
	fmt.Println("main 开始了")
	go task()
	go task()
	go task()
	go task()
	go task()
	go task()
	go task()
	time.Sleep(2*time.Second)
	fmt.Println("main 结束了")

}

3 信道

# 多个goroutine进行通信

package main

import (
	"fmt"
	"time"
)

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

//func main() {
//	// 定义信道
//	var a chan int // 定义了一个int类型的信道,信道中只能放int类型
//	// 放值
//	a <- 909
//	// 取值
//	//b:=<-a
//	//var b int = <-a
//	<-a  // 取出来,没有赋值给遍历
//
//}

func main() {


	//for i := 0; i < 10; i++ {
	//	go task1(i)
	//}
	//time.Sleep(2 * time.Second)


	//<nil>  定义并初始化
	// 默认信道取值,赋值都是阻塞的
	var a chan int=make(chan int)
	go task1(10,a)
	//fmt.Println(a)
	<-a  // 取值 ,如果没有值,会一直阻塞


}

func task1(i int,a chan int) {
	fmt.Println("task 开始 ", i)
	time.Sleep(1 * time.Second)
	fmt.Println("task 结束 ", i)
	a<-1  // 赋值,如果放值,没有其它协程取值,会阻塞在这
}

4 缓冲信道

5 锁

package main

import (
	"fmt"
	"sync"
)

//在学习 Mutex 之前,我们需要理解并发编程中临界区(Critical Section)的概念。
//当程序并发地运行时,多个 [Go 协程]不应该同时访问那些修改共享资源的代码。这些修改共享资源的代码称为临界区。
//var x  = 0
//func increment(wg *sync.WaitGroup,m *sync.Mutex) {
//	m.Lock()
//	x = x + 1
//	m.Unlock()
//	wg.Done()
//}
//func main() {
//	var w sync.WaitGroup
//	var m sync.Mutex  // 定义一把锁 ,值类型
//	for i := 0; i < 1000; i++ {
//		w.Add(1)
//		go increment(&w,&m)
//	}
//	w.Wait()
//	fmt.Println("final value of x", x)
//}

var x  = 0
func increment(wg *sync.WaitGroup, ch chan bool) {
	ch <- true
	x = x + 1
	<- ch
	wg.Done()
}
func main() {
	var w sync.WaitGroup
	ch := make(chan bool, 1)
	for i := 0; i < 1000; i++ {
		w.Add(1)
		go increment(&w, ch)
	}
	w.Wait()
	fmt.Println("final value of x", x)
}

6 异常处理

package main

import "fmt"

func f1()  {
	fmt.Println("我是f1")

}
func f2()  {

	defer func() {
		if err:=recover();err!=nil{
			//出了异常
			fmt.Println(err)
		}
		fmt.Println("finally ,永远会执行")
	}()
	fmt.Println("我是f2")
	var a []int
	fmt.Println(a[0])
}
func f3()  {
	fmt.Println("我是f3")

}

func main() {
	//defer fmt.Println("我最后执行")  // 先注册,后执行
	//defer fmt.Println("我最后执行3333")  // 先注册,后执行'
	//defer func() {
	//	fmt.Println("xxxxx")
	//}()
	//
	//defer f1()



	f1()

	f2()

	f3()

}

// defer: 延迟执行,即便程序出了异常,也会执行
// panic:主动抛出异常---->raise
// recover: 恢复程序,继续执行


/*
try:
	pass
except Exception as e:
	print(e)
finally:
	print('我永远会执行')
 */

/*
defer func() {
	if e:=recover();e!=nil{
		fmt.Println(e)
	}
	fmt.Println("我永远会执行")
}()
pass
 */

posted @ 2021-08-26 19:22  刘较瘦丫  阅读(92)  评论(0编辑  收藏  举报