Go语法的基本使用(三)

时间:2023-11-21 12:45:14
// 长度 vs 容量、
// 长度是目前里面有几个值
// 容量是最多能放多少个值
func main(){
var a =make(chan int,4)
a<-1
a<-2
a<-5
fmt.Println(len(a)) //3
fmt.Println(cap(a))// 45
<-a // 取值
fmt.Println(len(a)) // 2
fmt.Println(cap(a)) // 4
}

  一.协程

package main

import (
"fmt"
"time"
) //go 协程 func test() {
fmt.Println("hello go")
}
func main() {
//goroutine
go test()
go test()
go test()
go test()
go test()
go test()
go test()
time.Sleep(time.Second*2)
}

  二.值的存 和取

package main

import (
"fmt" ) // (2)信道 管道 通道 // 信道也是个变量
// 类型:信道运输的类型是int 类型
// 性质:是一种引用的类型 所以需要在初始化的时候就得付初始值 func task2(a chan bool) {
fmt.Println("hello go ")
// IO 一旦执行完毕,就往信道中放入一个值 a <- true // 存值
fmt.Println("")
} // 入口函数 理解 func main(){
// 必须初始化
var a chan bool = make(chan bool)
// 执行函数
go task2(a)
// 往里面存值 // <- a// 取值
x:=<-a
fmt.Println(x) }

------------恢复内容结束------------

  一. 在方法中使用 值 接收器 与 在函数中使用 值 参数

  (1)定义用一个外部函数(接收器:接收值)方法中使用值接收器方法

package main

import "fmt"

// 在方法中使用 值 接收器 与 在函数中使用 值 参数
// 在方法中使用 指针 接收器 与函数再使用 指针 参数
// 结构体
type Person5 struct{
name string
age int
sex int } // (1)定义用一个外部函数(接收器:接收值)方法中使用值接收器方法
func (a Person5)printName(){
fmt.Println(a.name)
fmt.Println(a.age)
fmt.Println(a.sex) } func main(){
// 定义一个变量
p:=Person5{name:"tt",age:18,sex:1}
// 调用值接收器
p.printName()

  (2)方法中使用指针接收器

package main

import "fmt"

// 函数中使用 指针传值

// (1)定义一个结构体
type Person2 struct {
name string
age int
sex int
} // (2)定义一个函数 中功能代码
func (a *Person2)printName(){
// 需要执行的功能 哈
fmt.Println(a.name)
fmt.Println(a.age)
} // (3)入口函数
func main(){
// 定义结构体的变量
// var t *Person2=&Person2{name:"tt",age:18,sex:2}
t:=&Person2{name:"tt",age:18,sex:2} // 值的传递可以省略类型
t.printName()
}

   

(3)函数的值传递和指针传递        

  函数中使用值参数

// (1)定义结构体
type Person2 struct{
name string
age string
sex int
id int
} // (2)定义一个外部功能函数 参数和结构体一一对应 其实还有返回值
func printName(a Person2){
fmt.Println(a.name)
fmt.Println(a.age)
fmt.Println(a.sex)
fmt.Println(a.id) } // (3)入口函数 >>>> url 地址的入口 func main() {
// (4)定义结构的变量的初始值
//p:=Person2{} //字符串则是 空 数字 则是0
//fmt.Println(p,"---==")
p:=Person2{name:"yy",age:"",sex:2} // 不设置数字就是0
printName(p) // 函数就是传值 接收器(a Person) p点方法
}

  

(4)函数中的指针传递参数

package main

import "fmt"

// (4)函数中的指针传递值

// (1)go语言定义结构体
type Person2 struct{
name string
age int
sex int
id int
} // (2)外部执行功能函数 func printName(a *Person2){
fmt.Println(a.name)
fmt.Println(a.age)
fmt.Println(a.sex)
fmt.Println(a.id) } // (3)入口函数
func main(){
// (4)定义变量及初始化
p:=&Person2{age:18,name:"yuyu",sex:1,id:13} // 指名道姓 无关顺序 printName(p) // &p和上面的一样获取地址 }   

  一.接收器如果不能进行识别需要进行重命名

package main

import "fmt"

// 在非结构体上的方法 》》》重命名 接收器
type MyInt int
func (i *MyInt) add(){
(*i)++
fmt.Println(*i) // 11 } func main() {
// 定义一个变量
var a MyInt=10
a.add() // 接收器传值
fmt.Println(a) // 引用11 }

  三,接口:是一系类方法的集合

  (1)实现方式一:接收器 传值  >>> mian 中点方法进行调用

package main

import "fmt"

// 接口 继承 封装 多态  ,鸭子类型  重点*****
// 接口:一系列方法的集合
// (1)语法:
// type 接口名 interface{
// test方法一()
// 方法二功能()
// } // >>>(1)定义一个鸭子类的接口
type Duck interface{
run()
speak() } // 结构体实现该接口(只要实现了接口中的所方法,该结构体实现了Duck接口)
// >>>(2)定义一普通胖鸭子类 结构体
type PDuck struct {
// 属性
name string
age string
id int } // (3)接口函数的值的传递
func (p PDuck) run(){
fmt.Println("我是第一只胖鸭子 会run") } func (p PDuck)speak(){
fmt.Println("我是第一只胖鸭子 会speak")
} // 定义一只唐老鸭 结构体
type TDuck struct { name string
age string
wife bool
} // 定义TDduct 的方法 不用函数实现
func (p TDuck) run(){
fmt.Println("我是唐老鸭 会run ")
fmt.Println(p.name)
} // 再定义一个speak 接收器方法 func (p TDuck) speat(){
fmt.Println("我是唐老鸭 会speak")
fmt.Println(p.wife,"") // } // (3)函数入口
func main(){
pD:=PDuck{name:"胖鸭子"}
tD:=TDuck{name:"唐老鸭"}
// 写一个函数:让鸭子说话,不管是唐老鸭还是胖鸭子
pD.speak() // 我是第一只胖鸭子 会speak 可以调
tD.speat() // 我是唐老鸭 会speak

  (2)实现接收器中函数的 run()  和speak() 方法  方法二:定义普通函数 在普通函数体内进行 run()  同时在我们的main中 调用 普通函数

package main

import "fmt"

// 接口 继承 封装 多态  ,鸭子类型  重点*****
// 接口:一系列方法的集合
// (1)语法:
// type 接口名 interface{
// test方法一()
// 方法二功能()
// } // >>>(1)定义一个鸭子类的接口
type Duck interface{
run()
speak() } // 结构体实现该接口(只要实现了接口中的所方法,该结构体实现了Duck接口)
// >>>(2)定义一普通胖鸭子类 结构体
type PDuck struct {
// 属性
name string
age string
id int } // (3)接口函数的值的传递
func (p PDuck) run(){
fmt.Println("我是第一只胖鸭子 会run") } func (p PDuck)speak(){
fmt.Println("我是第一只胖鸭子 会speak")
} // 定义一只唐老鸭 结构体
type TDuck struct { name string
age string
wife bool
} // 定义TDduct 的方法 不用函数实现
func (p TDuck) run(){
fmt.Println("我是唐老鸭 会run ")
fmt.Println(p.name)
} // 再定义一个speak 接收器方法 func (p TDuck) speat(){
fmt.Println("我是唐老鸭 会speak")
fmt.Println(p.wife,"") // } // (3)函数入口
func main(){
pD:=PDuck{name:"胖鸭子"}
tD:=TDuck{name:"唐老鸭"}
// 写一个函数:让鸭子说话,不管是唐老鸭还是胖鸭子
//pD.speak() // 我是第一只胖鸭子 会speak 可以调
//tD.speat() // 我是唐老鸭 会speak
//// speak(tD,"yyyy") //接收器 不是函数 不能传值
// 同时实现speak
speak2(tD) 调用普通函数
speak(pD)
// XXX(pD)
var d Duck
d=pD
// d=tD
fmt.Println(d,"xxxx") // {唐老鸭 false} xxxx }
// (4)函数 的传值
func speak(p PDuck){
p.speak() 调用接收器中的方法
} func speak2(p TDuck){
p.speat()
} func XXX(p PDuck){
p.run() // 在一个函数调用另一个函数
fmt.Println(p.name) 调用接收器的方法
}

  四、断言 switch 判断子类的属性和方法

package main

import "fmt"

// 接口 继承 封装 多态  ,鸭子类型  重点*****
// 接口:一系列方法的集合
// (1)语法:
// type 接口名 interface{
// test方法一()
// 方法二功能()
// } // >>>(1)定义一个鸭子类的接口
type Duck interface{
run()
speak() } // 结构体实现该接口(只要实现了接口中的所方法,该结构体实现了Duck接口)
// >>>(2)定义一普通胖鸭子类 结构体
type PDuck struct {
// 属性
name string
age string
id int } // (3)接口函数的值的传递
func (p PDuck) run(){
fmt.Println("我是第一只胖鸭子 会run") } func (p PDuck)speak(){
fmt.Println("我是第一只胖鸭子 会speak")
} // 定义一只唐老鸭 结构体
type TDuck struct { name string
age string
wife bool
} // 定义TDduct 的方法 不用函数实现
func (p TDuck) run(){
fmt.Println("我是唐老鸭 会run ")
fmt.Println(p.name)
} // 再定义一个speak 接收器方法 func (p TDuck) speat(){
fmt.Println("我是唐老鸭 会speak")
fmt.Println(p.wife,"") // } // (3)函数入口
func main(){
pD:=PDuck{name:"胖鸭子"}
tD:=TDuck{name:"唐老鸭"}
// 写一个函数:让鸭子说话,不管是唐老鸭还是胖鸭子
//pD.speak() // 我是第一只胖鸭子 会speak 可以调
//tD.speat() // 我是唐老鸭 会speak
//// speak(tD,"yyyy") //接收器 不是函数 不能传值
// 同时实现speak
speak2(tD) 调用普通函数
speak(pD)
// XXX(pD)
var d Duck
d=pD
// d=tD
fmt.Println(d,"xxxx") // {唐老鸭 false} xxxx }
// (4)函数 的传值
func speak(p PDuck){
p.speak() 调用接收器中的方法
} func speak2(p TDuck){
p.speat()
} func XXX(p PDuck){
p.run() // 在一个函数调用另一个函数
fmt.Println(p.name) 调用接收器的方法
}

截图suoshi:

Go语法的基本使用(三)

  空接口

package main

import "fmt"

// 空接口(一个方法都没有)
// 匿名空接口
// 所有的数据类型都实现了空接口
// 类似于一个父类
type Empty interface{ } type TDuck2 struct {
name string
age int
wife bool } // 入口函数
func main(){
test3(1)
test3("sss")
test3(TDuck2{})
test3(10.233432423) //var a Empty=1
//var b Empty="IOOIO"
} //func test(a Empty){
// fmt.Println(a)
//} func test3(a interface{}) {
switch a.(type) {
case int:
fmt.Println("int类型")
case string:
fmt.Println("string")
case TDuck2:
fmt.Println("老鸭子")
default:
fmt.Println("啥类型")
}

  五.异常处理

package main

import (
"fmt" ) // 异常处理
// defer 延迟调用 即便程序出现严重错误 也会执行
// panic 就是python中的raise(主动跑出异常)
// recover 恢复程序, 继续执行 func main() {
//先注册,后调用
//defere ????
fmt.Println("xxx")
// defere
fmt.Println("yyyy")
//f1() // 调用
f2() // 调用
//f3() // 调用
} func f1(){
fmt.Println("f1...") } func f2(){
defer func() {
if a:=recover();a!=nil{
// a 如果不等于nil, 表示程序出了异常, a就是异常信息
// a 等于nil 表示没有异常
fmt.Println("代码异常出错;了")
}//用于会被执行(相当于finally) }() // 这里执行函数
fmt.Println("f2...")
// var a = make([]int,3,3)
// fmt.Println(a[4])
panic("主动抛异常")
}
func f3(){
fmt.Println("f3...")
}

  六。自定义set       map 去重

package main

import "fmt"

// (1)自定义set() 可以放值

type MySet map[interface{}]bool
//func (s MySet)isExist(a interface{}) bool {
// return s[a] // 这只是个接口 判断
//} // 定义接口函数 interface{} 其实大可不必要用*号
func (s *MySet) set(a interface{}){
(*s)[a]=true //
} //用函数 就是一个普通的接收器函数// 可以查看长度
func (s MySet)len()int {
return len(s)
} // // 可以打印所有内容 MySet 》》》 类接收器
func (a MySet)printAll(){
for k,v:=range a{// 关键字range + s 变量
fmt.Println(k,v,"000--")
}
} func main() { // MySet = map[interface{}]bool 这个类型
var a MySet=make(MySet)
fmt.Println(a) // 空类型map[]
a.set("")
a.set("")
a.set("")
fmt.Println(len(a))
fmt.Println(a)
fmt.Println(a.len())
a.printAll() }

  七.信道

  (1)只写信道

package main

import "fmt"

// 单向信道只能放或 取 chan 关键字 a:=<-b 取    a<- 存取 箭头
func sendData(sendch chan<-int){
sendch<-10
} func main(){
//只写信道
sendch :=make(chan int)
go sendData(sendch)
fmt.Println(<-sendch)
}

  (信道死锁的问题)

package main

import "fmt"

// 单向信道只能放或 取
//func sendData(sendch chan<-int){
// sendch<-10
//}
//
//func main(){
// //只写信道
// sendch :=make(chan int)
// go sendData(sendch)
// fmt.Println(<-sendch)
//} // 关闭信道和使用 for range 遍历信道 func task3(ccc chan int){
for i:=0;i<10;i++{
ccc<-i
}
close(ccc) // 关闭即可
} func main(){
// 类型定义
c:=make(chan int)
go task3(c)
// 死循环在监听我们的事件
for {
v,ok:=<-c
// 如果信道关闭,OK就是false
if ok==false{
break
}
fmt.Println("打印",v,ok)
} } // 出现死锁:fatal error: all goroutines are asleep - deadlock!
// 在for 循环结束后关闭存储任务 即可 解决死锁问题

  2.信道缓存  》》》 设定缓存大小

(1)

package main

import "fmt"

// 信道缓冲
func main(){
// 初始化
var t chan int=make(chan int,1) // 0 前期缓存值
t<-1 // 将1 存入a 信道中 不写默认为0 根本存不进去
b:=<-t
fmt.Println("xxx",b)
}

  (2)容量

package main

import (
"fmt"
"time"
) // 列子 func write(ddd chan int){
// ddd 就相当于一个容器
for i:=0;i<10;i++{
ddd<-i }
close(ddd) } // 入口函数
func main() {
// 初始定义类型和信道类型 和 容量
var ddd chan int=make(chan int,5)
go write(ddd)
// 做io
time.Sleep(2*time.Second)
for v:=range ddd{
fmt.Println("reader value",v,"from ddd")
time.Sleep(2*time.Second)
} }

  (3)容量和长度

// 长度 vs 容量、
// 长度是目前里面有几个值
// 容量是最多能放多少个值
func main(){
var a =make(chan int,4)
a<-1
a<-2
a<-5
fmt.Println(len(a)) //3
fmt.Println(cap(a))// 45
<-a // 取值
fmt.Println(len(a)) // 2
fmt.Println(cap(a)) // 4
}

   (4)sync.WaitGroup

package main

import (
"fmt"
"sync"
"time"
) // waitgroup:等待所有go协程执行完成
func task4(wg *sync.WaitGroup,i int){
time.Sleep(time.Second*2)
fmt.Println(i)
wg.Done() //
} func main(){
// sync包下的waitGroup,是个值类型,当参传递,需要地址
var wg sync.WaitGroup // 定义
for i:=0;i<5;i++ {
//wg.Add表示标志了起了一个goroutine
wg.Add(1)
go task4(&wg, i)
}
// 等待所有协程执行完成
wg.Wait()
fmt.Println("都执行完了")
}

  (5)通过信道实现

//package main
//
//import (
//"fmt"
//"sync"
//"time"
//)
//
//// waitgroup:等待所有go协程执行完成
//func task4(wg *sync.WaitGroup,i int){
// time.Sleep(time.Second*2)
// fmt.Println(i)
// wg.Done() //
//}
//
//func main(){
// // sync包下的waitGroup,是个值类型,当参传递,需要地址
// var wg sync.WaitGroup // 定义
// for i:=0;i<5;i++ {
// //wg.Add表示标志了起了一个goroutine
// wg.Add(1)
// go task4(&wg, i)
// }
// // 等待所有协程执行完成
// wg.Wait()
// fmt.Println("都执行完了")
//
//}
package main import (
"fmt"
"time"
) // 通过信道实现
func main(){
var a =make(chan bool)
for i:=0;i<5;i++{
go task6(a,i) // 将信道和i 值传送到我们的函数中
}
for i:=0;i<5;i++{
<-a // 取值
}
fmt.Println("都执行完了")
}
// 传值传几个接收几个 以及类型 func task6(a chan bool,i int){
time.Sleep(time.Second*2)
fmt.Println(i)
a<-true // 将值存入我们a 信道中 }

  七。中的锁

package main

import (
"fmt"
"sync"
) // go 中的锁实现数据的安全 // 功能
var x=0
func incrament(wg *sync.WaitGroup,m *sync.Mutex){
// 布置锁
m.Lock()
x = x+10
m.Unlock()
wg.Done()
fmt.Println(x) // 从10开始 } func main(){
var w sync.WaitGroup // 定义变量
var m sync.Mutex // 定义锁 // 值类型 ,传递地址
for i:=0;i<1000;i++{
w.Add(1)
go incrament(&w,&m) }
w.Wait()
fmt.Println("都执行完毕了",x) // 拿到最后的值
}

  (2)信道也是保证数据安全?

//package main
//
//import (
// "fmt"
// "sync"
//)
//
//// go 中的锁实现数据的安全
//
//// 功能
//var x=0
//func incrament(wg *sync.WaitGroup,m *sync.Mutex){
// // 布置锁
// m.Lock()
// x = x+10
// m.Unlock()
// wg.Done()
// fmt.Println(x) // 从10开始
//
//}
//
//
//func main(){
// var w sync.WaitGroup // 定义变量
// var m sync.Mutex // 定义锁 // 值类型 ,传递地址
// for i:=0;i<1000;i++{
// w.Add(1)
// go incrament(&w,&m)
//
// }
// w.Wait()
// fmt.Println("都执行完毕了",x) // 拿到最后的值
//} // 通过信到实现数据的存值
package main import (
"fmt"
"sync"
)
var x=0
func increment(w *sync.WaitGroup,ch chan bool){
ch<-true // 进行存储
x=x+10
<-ch
w.Done() // 执行
fmt.Println(x,"执行x")
} func main(){
var w sync.WaitGroup // 定义一个
ch :=make(chan bool,1)
for i:=0;i<5;i++{
w.Add(1)
go increment(&w,ch) }
w.Wait()
fmt.Println("final value ofx",x) }