2022/02/14 今天又是不熬夜的一天,舒服~
package main
import (
"fmt"
"time"
)
func main() {
//管道可以声明为只读或者只写
//1.在默认情况下,管道是双向的
//var chan1 chan int //可读可写
//2.声明为只写
var chan2 chan<- int
chan2 = make(chan int, 3)
chan2 <- 20
//3.声明为只读
var chan3 <-chan int
chan3 = make(<-chan int, 2)
num2 := <-chan3
fmt.Println("num2", num2)
/*
可以通过函数传参把双向管道传入实参,
函数可以用可读或可写管道接收,防止误操作
*/
//*********使用select可以解决从管道取数据的阻塞问题
intChan := make(chan int, 10)
for i := 0; i < 10; i++ {
intChan <- i
}
stringChan := make(chan string, 5)
for i := 0; i < 5; i++ {
stringChan <- "hello" + fmt.Sprintf("%d", i)
}
/*
传统的方法在遍历管道时,如果不关闭会阻塞导致 deadlock
在实际开发中,可能不好确定声明时候关闭管道
可以使用select方式解决
*/
label:
for {
select {
//如果这里intChan一直没有关闭,不会一直阻塞而deadlock
case v := <-intChan:
fmt.Println("从intChan读取了数据\n", v)
time.Sleep(time.Second)
case v := <-stringChan:
fmt.Println("从stringChan读取了数据\n", v)
time.Sleep(time.Second)
default:
fmt.Println("都读取不到了,溜了")
time.Sleep(time.Second)
break label
}
}
}
package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Println("hello world")
}
}
func test() {
/*
panic: assignment to entry in nil map
这里会报panic,原因是没有给map make空间
主线程中启动两个协程,这个协程panic导致整个程序崩溃,如果希望
test()协程不影响到其他协程的运行,可以用 defer + recover
*/
defer func() {
if err := recover(); err != nil {
fmt.Println("test()发生错误", err)
//这里可以用发邮件或者其他提示开发人员有错误出现
//不会影响到其他协程,只会终止本协程
}
}()
var myMap map[int]string
myMap[0] = "hello"
}
func main() {
go sayHello()
go test()
for i := 0; i < 10; i++ {
fmt.Println("主线程")
time.Sleep(time.Second)
}
}
package main
import (
"fmt"
"reflect"
)
/*
反射要注意的细节
1.reflect.Value.Kind 获取变量的类别,返回的是一个常量(看手册)
*/
/*
编写一个案例,
演示对基本数据类型,interface{}, reflect.Value进行反射的基本操作
*/
//专门演示反射
func reflectTest01(b interface{}) {
//通过反射获取传入的变量的type-类型, kind-类别, 值
//1.先获取到reflect.Type
rType := reflect.TypeOf(b)
fmt.Println("rType = ", rType) //rType = int
//2.获取到reflect.Value
rValue := reflect.ValueOf(b)
fmt.Println("rValue = ", rValue) //rValue = 100
/*这里需要注意这个100不是num的100,而是反射的value值*/
//获取变量的kind //两种方法取出来的是一样的
fmt.Println("rType kind = ", rType.Kind()) //rType kind = int
fmt.Println("rValue kind = ", rValue.Kind()) //rValue kind = int
n1 := 10
n2 := 2 + n1
fmt.Println("n2 = ", n2)
//n3 := 2 + rValue //cannot convert 2 (untyped int constant) to struct{reflect.flag}
/* */
fmt.Printf("rValue = %v, rValue type = %T\n", rValue, rValue)
/*rValue = 100, rValue type = reflect.Value*/
/*通过方法可以获取出 rValue 的值*/
n4 := 2 + rValue.Int() //放入的是int值,可以直接用方法,其他的类型也有方法
fmt.Println("n4 = ", n4)
//如果要把 rValue重新转换成interface{},用断言,再转换成int
num5 := rValue.Interface()
num6 := num5.(int)
fmt.Println("num6 = ", num6)
}
func main() { //对变量的反射
var num int = 100
reflectTest01(num)
}
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string
Age int
}
func reflectTest02(stu interface{}) {
//1.先获取到reflect.Type
rType := reflect.TypeOf(stu)
fmt.Println("rType = ", rType) //rType = main.Student
//2.获取到reflect.Value
rValue := reflect.ValueOf(stu)
fmt.Println("rValue = ", rValue) //rValue = {levi 18}
//3.将rValue抓成 interface{}
iV := rValue.Interface()
fmt.Printf("iV = %v, iV Type = %T\n", iV, iV) //iV = {levi 18}, iV Type = main.Student
//4.我们要把接口断言转成需要的类型才能取出结构体中的数据
/* 可以用switch更加灵活
switch iV.(type) {
case Student:
fmt.Println("断言为Student结构体")
}
*/
myStu, ok := iV.(Student)
if ok {
fmt.Println("stu.Name = ", myStu.Name)
}
}
func main() { //对结构体的反射
stu := Student{"levi", 18}
reflectTest02(stu)
}
package main
import "fmt"
/*
常量介绍
1.常量使用const修饰
2.常量在定义的时候,必须初始化
3.常量不能修改
4.常量只能修饰bool,数值类型(int,float系列),string类型
5.语法:const identifier [type] = value
6.常量也是通过首字母的大小写来控制访问范围
*/
func main() {
//1.2
const tax int = 0
//3.error
//tax = 10//cannot assign to tax (constant 0 of type int)
const name = "levi"
const t float64 = 0.8
//const a int //err
const q = 9 / 3 // 9/3是常量值,没问题
//num := 2
//const c = 8 / num //err,编译器认为num是变量,
//num是不确定的可变的,但是c又是不可变的
//比较简洁的写法
const (
a = 1
b = 2
)
//还有一种专业的写法,像枚举
const (
p = iota // p默认为0
o
i
u
)
fmt.Printf("p = %d, o = %d, i= %d, u = %d\n", p, o, i, u)
//p = 0, o = 1, i= 2, u = 3
const (
p1 = iota // iota默认为0
o1 = iota
i1, u1 = iota, iota
)
fmt.Printf("p1 = %d, o1 = %d, i1 = %d, u1 = %d\n", p1, o1, i1, u1)
//p1 = 0, o1 = 1, i1 = 2, u1 = 2
// iota 默认是0 换行会+1, 在一行里面值不会变
}