简介
安装 1、注意 环境变量中 GOPATH; GOROOT的配置。
2、还要 注意 是 模块模式还是 gopath模式。
3、用vscode编辑器时一定要记得在编辑器中 指定gopath的路径,不然会找不到。
杂鱼笔记 1、go 一个方法内重复定义 变量非法;
2、go 没有隐式类型转换,变量声明和赋值要一致;
3、go 声明变量 有个默认值;
4、go有类型推断;
5、 用vscode时,注意 go 代码规范是 冗余非法,一定要先在代码块中用到了 某个 库,再写 import,不然直接保存会导致 编辑器 把 冗余import 库直接当写错了删除。
6、uint8 这样的无符号 整型 范围是 2^7 + 2^7-1 = 0255 , 整数部分是 int8 -128127的两倍。
7、go 用反引号 `` 输出带特殊符号的原始字符串.
8、go 的 string 转其它类型一定要保证 能够转,不然会按照 目标类型的默认值来 赋值;
指针 0、指针概念;
1 2 3 4 5 6 7 8 9 10 11 12 package mainimport "fmt" func main () { var age int = 18 fmt.Println(&age) var ptr *int = &age fmt.Println("ptr存储空间的地址为:" , &ptr) fmt.Println("ptr指向的数值为:" , *ptr) }
1、可以通过指针来改变指向值;
1 2 3 4 5 6 7 8 9 10 package mainimport "fmt" func main () { var age int = 18 var ptr *int = &age *ptr = 20 fmt.Println(age) }
2、指针变量接收的一定是地址值;
3、指针变量的定义一定要和实际值匹配,例如 *float 类型的指针 就不能和 &num num 是一个 int8 类型的变量地址匹配;
标识符 ‘_’ 只能被当作忽略的标识符,不能单独当作标识符使用。
1、main包 是一个程序的入口包,main函数所在的包,建议定义为main包;
2、变量名、函数名、常量 首字母大写,则可以被其它包访问,首字母小写则只能本包中使用;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export GO111MODULE=off package mainimport ( "fmt" "goproject/demo_package/test" ) func main () { fmt.Println(test.StuNo) }
3、go语言获取控制台输入的 时候,scanln、scanf 传入的是待修改 值的地址 如 &age.
分支结构 go 的 switch case 中 加上 fallthrough 会带来 一层的穿透。
goto 到某个标签的 语句最好少用,因为可能导致 逻辑混乱。
函数 go不支持 函数重载(同一函数 不同形参)
利用指针,实现一个函数内改变函数外的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport "fmt" var str string = "abcdefg" func fun (args ...*int ) { for i := range args { *args[i] = 30 fmt.Print("fun=====" , *args[i]) } } func main () { var age int = 10 fun(&age) fmt.Print("main----- " , age) }
函数直接当形参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport "fmt" func fun (num int ) { fmt.Println(num) } func test (num1 int , num2 float32 , testFunc func (int ) ) { fmt.Println("---test" ) } func main () { a := fun test(1 , 3.14 , a) }
go支持自定义类型
1 2 3 4 5 type myFunc func (int ) func test01 (num1 int , num2 float64 , testFunc myFunc) { fmt.Println("---test01" ) }
go支持对函数返回值命名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func test02 (num1 int , num2 int ) (sum int , sub int ) { sum = num1 + num2 sub = num1 - num2 return } func main () { a := fun test(1 , 3.14 , a) test(10 , 3.14 , fun) test01(10 , 3.14 , a) sub, sum := test02(10 , 6 ) fmt.Println(sub, sum) }
包 包是一个抽象概念,需要用 package 来声明一下。 导包,import 其实是导入 package 声明包文件所在的文件夹路径。
导入另一个包的操作是import 从 gopath 的src 下的路径开始算的,并且只有首字母大写的方法才能被别的包访问。
建议1\ package 进行包的声明,建议 声明的包和所在的文件夹同名;建议2\ main包是程序的入口包,一般main函数放在这个包下。
是哪一个包 ,要看 package 声明 叫什么名字,包就是什么名字,main函数一定要放在main包下。
一个目录下不能有重复的函数
同级别源文件的包的声明,必须一致!也就是说一个包其实对应一个文件夹。
匿名函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" var Fanc = func (num1 int , num2 int ) int { return num1 * num2 } func main () { result := func (num1 int , num2 int ) int { return num1 + num2 }(10 , 20 ) sub := func (num1 int , num2 int ) int { return num1 - num2 } fmt.Println(result) fmt.Println(sub(20 , 10 )) fmt.Println(Fanc(2 , 3 )) }
闭包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport "fmt" func getSum () func (int ) int { var sum int = 0 return func (num1 int ) int { sum = sum + num1 return sum } } func main () { f := getSum() fmt.Println(f(1 )) fmt.Println(f(2 )) fmt.Println(f(3 )) }
defer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" func main () { result := add(100 , 200 ) fmt.Println(result) } func add (num1 int , num2 int ) int { defer fmt.Println("num1=" , num1) defer fmt.Println("num2=" , num2) num1 += 10 num2 += 20 var sum int = num1 + num2 fmt.Println(sum) return sum }
字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package mainimport ( "fmt" "strconv" "strings" ) func main () { str := "golang你好" fmt.Println(len (str)) for i, value := range str { fmt.Printf("索引为:%d,值为: %c\n" , i, value) } r := []rune (str) for i := 0 ; i < len (r); i++ { fmt.Printf("%c \n" , r[i]) } num1, _ := strconv.Atoi("888" ) fmt.Println(num1) str1 := strconv.Itoa(88 ) fmt.Println(str1) count := strings.Count("golangisbestonegolang" , "go" ) fmt.Println(count) fmt.Println(strings.Index("golangisbestonegolang" , "go" )) str2 := strings.Replace("golangisbest" , "golang" , "python" , -1 ) str3 := strings.Replace("golangisbest" , "g" , "python" , 2 ) fmt.Println(str2) fmt.Println(str3) arr := strings.Split("go-python-java" , "-" ) fmt.Println(arr) fmt.Println(strings.ToLower("ABC" )) fmt.Println(strings.ToUpper("AbC" )) fmt.Println(strings.TrimSpace(" go and java " )) fmt.Println(strings.Trim("~go and java~" , "~" )) fmt.Println(strings.HasPrefix("http://baidu.com" , "http" )) }
new 1 2 3 4 num := new (int ) fmt.Printf("num type is:%T,num value is:%v,num index is:%v,num指针指向的值是:%v" , num, num, &num, *num)
异常捕获 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package mainimport ( "errors" "fmt" ) func main () { test() fmt.Println("上面执行成功" ) fmt.Println("开始执行下面的逻辑" ) err := test2() if err != nil { fmt.Println("自定义错误:" , err) panic (err) } fmt.Println("test2上面执行成功" ) fmt.Println("test2开始执行下面的逻辑" ) } func test () { defer func () { err := recover () if err != nil { fmt.Println("异常被捕获" ) fmt.Println("err 是:" , err) } }() num1 := 10 num2 := 0 result := num1 / num2 fmt.Println(result) } func test2 () (err error ) { num1 := 10 num2 := 0 if num2 == 0 { return errors.New("除数不能为0" ) } else { result := num1 / num2 fmt.Println(result) return nil } }
数组 定义好的指针,默认值都是0;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" func main () { var scores [3 ]int var sum int = 0 for i := 0 ; i < len (scores); i++ { fmt.Printf("please enter %d_th score\n" , i+1 ) fmt.Scanln(&scores[i]) } for i := 0 ; i < len (scores); i++ { sum += scores[i] } avg := sum / len (scores) fmt.Println(sum, avg) }
1 2 3 4 var scores [3 ]int = [3 ]int {1 , 3 , 9 }var scores = [3 ]int {1 , 2 , 3 }var scores = [...]int {1 , 2 , 3 }var scores = [...]int {0 : 99 , 2 : 100 , 1 : 1 }
go 语言中的数组默认是值传递,和python等语言不一样,但是可以通过改变参数为指针,实现和python等语言一样的参数传递;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package mainimport "fmt" func main () { var arr1 = [3 ]int {3 , 6 , 9 } fmt.Printf("1类型是 %T\n" , arr1) var arr2 = [6 ]int {1 , 2 , 3 , 4 , 5 , 6 } fmt.Printf("2类型是 %T\n" , arr2) test(arr1) fmt.Println(arr1) test2(&arr1) fmt.Println(arr1) } func test (arr [3]int ) { arr[0 ] = 100 } func test2 (arr *[3]int ) { (*arr)[0 ] = 200 }
切片 1 2 3 4 5 6 7 8 9 10 package mainimport "fmt" func main () { var intarr = [6 ]int {1 , 2 , 3 , 4 , 5 , 6 } var slice []int = intarr[:3 ] fmt.Println(slice) fmt.Println("容量is:" , cap (slice)) }
注意切片并不是数组,而是一个单独的结构体;
由于 切片 存的是数组的地址,所以改变切片的值,原本数组的值也会跟着变;
make 用 make 方法创建一个切片;
1 2 3 4 5 6 7 8 9 10 11 12 package mainimport "fmt" func main () { slice := make ([]int , 3 , 20 ) fmt.Println(slice) fmt.Println("len is " , len (slice)) slice[1 ] = 666 fmt.Println(slice) }
切片注意事项
【1】切片不用直接使用,需要引用一个数组 或者make提供一个空间供切片使用;
【2】切片可以继续切片;
【3】切片可以动态增长。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport "fmt" func main () { var intarr [3 ]int = [3 ]int {1 , 2 , 3 } slice := intarr[1 :] fmt.Println(slice) slice2 := append (slice, 88 , 99 , 100 ) fmt.Println("slice2 is :" , slice2) fmt.Println("slice is :" , slice) slice = append (slice, 111 , 222 , 333 ) fmt.Println(slice) }
1 2 3 4 5 6 7 8 9 10 11 package mainimport "fmt" func main () { var a []int = []int {1 , 2 , 3 } var b []int = make ([]int , 10 ) copy (b, a) fmt.Println(b) }
map 就是python中的dict
1 2 3 4 5 6 7 8 9 10 11 package mainimport "fmt" func main () { var a map [int ]string a = make (map [int ]string , 10 ) a[123929 ] = "张三" a[2234234 ] = "李四" fmt.Println(a) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport "fmt" func main () { var a map [int ]string a = make (map [int ]string , 10 ) a[123929 ] = "张三" a[2234234 ] = "李四" fmt.Println(a) b := make (map [int ]string ) b[123123 ] = "zhansan" b[32143222 ] = "liudehua" b[1231234 ] = "zhouxinchi" fmt.Println(b) c := map [int ]string { 200200 : "张三" , 899898 : "王五" , } c[123982 ] = "刘德华" fmt.Println(c) delete (c, 200200 ) fmt.Println(c) value, flag := b[123123 ] fmt.Println(value, flag) for k, v := range a { fmt.Printf("key is :%v, value is :%v \n" , k, v) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport ( "fmt" ) func main () { a := make (map [string ]map [int ]string ) a["class1" ] = make (map [int ]string ) a["class1" ][200 ] = "小王" a["class1" ][300 ] = "小红" a["class2" ] = make (map [int ]string ) a["class2" ][100 ] = "李辉" a["class2" ][200 ] = "小宁" for k, v := range a { fmt.Println("班级是:" , k) for k1, v1 := range v { fmt.Printf("学生学号是:%v,学生姓名是:%v\n" , k1, v1) } } }
go的面向对象 go 不用类,用结构体。
结构体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" type Teacher struct { Name string Age int School string } func main () { var ma Teacher fmt.Println(ma) ma.Name = "马云" ma.Age = 59 ma.School = "杭州师范" fmt.Println(ma) fmt.Println(ma.Age + 10 ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport "fmt" type Teacher struct { Name string Age int School string } func main () { var ma Teacher = Teacher{"赵云" , 25 , "白马义从" } fmt.Println(ma) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport "fmt" type Teacher struct { Name string Age int School string } func main () { var t *Teacher = new (Teacher) (*t).Age = 100 (*t).Name = "好人" fmt.Println(*t) t.Name = "坏人" t.Age = 95 fmt.Println(*t) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport "fmt" type Teacher struct { Name string Age int School string } func main () { var t *Teacher = &Teacher{} (*t).Name = "赵云" (*t).Age = 25 t.School = "白马义从" fmt.Println(*t) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport "fmt" type Teacher struct { Age int } type Tea Teachertype Person struct { Age int } func main () { var t Teacher = Teacher{10 } var p Person = Person{10 } t = Teacher(p) fmt.Println(t) fmt.Println(p) var t1 Tea = Tea{100 } t = Teacher(t1) fmt.Println(t1) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" type Student struct { Name string Age int } func main () { var s1 Student = Student{"小王" , 22 } fmt.Println(s1) var s2 Student = Student{ Name: "小红" , Age: 33 , } fmt.Println(s2) var s3 *Student = &Student{"小明" , 30 } fmt.Println(s3) }
方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" type Person struct { Age int } func (p Person) test() { p.Age = 111 fmt.Println(p.Age) } func main () { var p Person p.Age = 100 p.test() fmt.Println(p.Age) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" type Person struct { Age int } func (p *Person) test() { (*p).Age = 2333 fmt.Printf("test 中p存好的内容是 %p\n" , p) fmt.Println(p.Age) } func main () { var p Person p.Age = 100 fmt.Printf("main 中p存放的地址是 %p\n" , &p) (&p).test() fmt.Println(p.Age) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" type integer int func (i integer) print () { i = 10 fmt.Println("print i = " , i) } func (i *integer) change() { *i = 30 fmt.Println("change i = " , *i) } func main () { var i integer = 20 fmt.Println("main i = " , i) i.print () fmt.Println("main i = " , i) i.change() fmt.Println("main i = " , i) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" type student struct { Name string Age int } func (s *student) String() string { str := fmt.Sprintf("Name = %v,Age = %v" , s.Name, s.Age) return str } func main () { stu := student{ Name: "周文王" , Age: 20 , } fmt.Println(&stu) }
函数 要严格按照 参数是 值还是指针来区分,但是方法不一样。
方法 接收者为 值类型,可以传入指针类型,接收者是 指针类型,也可以传入值类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package mainimport "fmt" type student struct { Name string Age int } func (s student) test01() { fmt.Println(s.Name, s.Age) } func (s *student) test02() { (*s).Name = "小黄" fmt.Println((*s).Name) } func main () { var s student = student{"小红" , 100 } s.test01() (&s).test01() s.test02() (&s).test02() }
用工厂模式实现非首字母大写的结构体的跨包调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package modeltype Student struct { Name string Age int } type student struct { Name string Age int } func New_student (n string , a int ) student { return student{n, a} } func New_student_address (n string , a int ) *student { return &student{n, a} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport ( "demo15/model" "fmt" ) func main () { var s model.Student = model.Student{"张三" , 11 } fmt.Println(s) ss := model.New_student("李四" , 12 ) fmt.Println(ss.Name, ss.Age) fmt.Printf("类型是:%T\n" , ss) sss := model.New_student_address("王五" , 13 ) fmt.Println((*sss).Name, (*sss).Age) fmt.Printf("类型是:%T\n" , sss) }
封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package modelimport "fmt" type person struct { Name string age int } func NewPerson (name string ) *person { return &person{ Name: name, } } func (p *person) SetAge(age int ) { if age > 0 && age < 150 { p.age = age } else { fmt.Println("范围不正确." ) } } func (p *person) GetAge() int { return p.age }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package mainimport ( "demo16/model" "fmt" ) func main () { p := model.NewPerson("丽丽" ) p.SetAge(20 ) fmt.Println(p.Name) fmt.Println(p.GetAge()) fmt.Println(p) }
继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "fmt" ) type Animal struct { Age int Weight float32 } func (a *Animal) Shout() { fmt.Println("wan wan wan " ) } type Cat struct { Animal } func (c *Cat) scratch() { fmt.Println("闹人" ) } func main () { cat := &Cat{} cat.Animal.Age = 3 cat.Animal.Weight = 10.3 cat.Animal.Shout() cat.scratch() }
就近原则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package mainimport ( "fmt" ) type Animal struct { Age int Weight float32 } func (a *Animal) Shout() { fmt.Println("wan wan wan " ) } func (a *Animal) showInfo() { fmt.Println("年龄是:" , a.Age) } type Cat struct { Animal Age int } func (c *Cat) showInfo() { fmt.Println("年龄是:" , c.Age) } func (c *Cat) scratch() { fmt.Println("闹人" ) } func main () { cat := &Cat{} cat.Age = 9 cat.Weight = 10.3 cat.Animal.Age = 20 cat.showInfo() cat.Animal.showInfo() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "fmt" ) type A struct { a int b string } type B struct { c int d string a int } type C struct { A B } func main () { c := C{A{10 , "aaa" }, B{20 , "bbb" , 30 }} fmt.Println(c) fmt.Println(c.b) fmt.Println(c.A.a, c.B.a) }
结构体的匿名字段可以是基本数据类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" ) type A struct { a int b string } type B struct { c int d string a int } type C struct { A B int } func main () { c := C{A{10 , "aaa" }, B{20 , "bbb" , 30 }, 888 } fmt.Println(c) fmt.Println(c.b) fmt.Println(c.A.a, c.B.a) fmt.Println(c.int ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package mainimport ( "fmt" ) type A struct { a int b string } type B struct { c int d string a int } type C struct { A B int } type C1 struct { *A *B int } type D struct { a int b string c B } func main () { c := C{A{10 , "aaa" }, B{20 , "bbb" , 30 }, 888 } fmt.Println(c) fmt.Println(c.b) fmt.Println(c.A.a, c.B.a) fmt.Println(c.int ) c1 := C1{&A{10 , "aaa" }, &B{20 , "bbb" , 30 }, 888 } fmt.Println(c1) fmt.Println(c1.A) fmt.Println(*c1.A) d := D{10 , "ooo" , B{10 , "bbb" , 100 }} fmt.Println(d) fmt.Println(d.c.d) }
接口(借尸还魂) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport "fmt" type SayHello interface { sayHello() } type Chinese struct {} func (person Chinese) sayHello() { fmt.Println("你好" ) } type American struct {} func (person American) sayHello() { fmt.Println("hi" ) } func greet (s SayHello) { s.sayHello() } func main () { c := Chinese{} a := American{} greet(c) greet(a) }
一个结构体实现多个接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" type AInterface interface { a() } type BInterface interface { b() } type Stu struct {} func (s Stu) a() { fmt.Println("aaaa" ) } func (s Stu) b() { fmt.Println("bbbb" ) } func main () { var s Stu var a AInterface = s var b BInterface = s a.a() b.b() }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport "fmt" type AInterface interface { a() } type BInterface interface { b() } type CInterface interface { AInterface BInterface c() } type Stu struct {} func (s Stu) a() { fmt.Println("aaaa" ) } func (s Stu) b() { fmt.Println("bbbb" ) } func (s Stu) c() { fmt.Println("ccc" ) } func main () { var s Stu var a AInterface = s var b BInterface = s a.a() b.b() var c CInterface = s c.c( ) }
空接口 没有实现任何方法,所以可以视为 任意类型都实现了空接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 type E interface {} func main () { var s Stu var a AInterface = s var b BInterface = s a.a() b.b() var c CInterface = s c.c() var e E = s fmt.Println(e) var ee interface {} = s fmt.Println(ee) }
多态 golang的多态 也是通过 接口 实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport "fmt" type SayHello interface { sayHello() } type Chinese struct {} func (person Chinese) sayHello() { fmt.Println("你好" ) } type American struct {} func (person American) sayHello() { fmt.Println("hi" ) } func greet (s SayHello) { s.sayHello() } func main () { c := Chinese{} a := American{} greet(c) greet(a) }
断言 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package mainimport "fmt" type SayHello interface { sayHello() } type Chinese struct { name string } func (person Chinese) sayHello() { fmt.Println("你好" ) } func (person Chinese) niu() { fmt.Println("扭秧歌" ) } type American struct { name string } func (person American) sayHello() { fmt.Println("hi" ) } func greet (s SayHello) { s.sayHello() var ch Chinese = s.(Chinese) ch.niu() } func main () { c := Chinese{"陈" } greet(c) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package mainimport "fmt" type SayHello interface { sayHello() } type Chinese struct { name string } func (person Chinese) sayHello() { fmt.Println("你好" ) } func (person Chinese) niu() { fmt.Println("扭秧歌" ) } type American struct { name string } func (person American) sayHello() { fmt.Println("hi" ) } func greet (s SayHello) { s.sayHello() ch, flag := s.(Chinese) if flag == true { ch.niu() } else { fmt.Println("不会扭秧歌" ) } } func main () { a := American{"宇" } greet(a) }
文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package mainimport ( "fmt" "os" ) func main () { file, err := os.Open("/Users/chenyushao/Desktop/golang_draft/test.txt" ) if err != nil { fmt.Println("文件打开失败,对应错误为:" , err) } else { fmt.Println("文件的指针是:" , file) } err = file.Close() if err != nil { fmt.Println("关闭失败" ) } else { fmt.Println("关闭成功" ) } }
带缓冲的读取,4096.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport ( "bufio" "fmt" "io" "os" ) func main () { file, err := os.Open("/Users/chenyushao/Desktop/golang_draft/test.txt" ) if err != nil { fmt.Println("文件打开成功。" ) } defer file.Close() reader := bufio.NewReader(file) for { str, err := reader.ReadString('\n' ) if err == io.EOF { fmt.Println("读取完毕" ) break } fmt.Println(str) } fmt.Println("文件读物成功,且读取完毕。" ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package mainimport ( "bufio" "fmt" "os" ) func main () { file, err := os.OpenFile("/Users/chenyushao/Desktop/golang_draft/test.txt" , os.O_APPEND|os.O_RDWR|os.O_CREATE, 0751 ) if err != nil { fmt.Println("打开文件失败," , err) return } defer file.Close() writer := bufio.NewWriter(file) writer.WriteString("hello " ) for i := 0 ; i < 10 ; i++ { writer.WriteString("重复" ) } writer.Flush() }
进程、线程、协程、管道 一个运行的程序就是一个 进程;
一个进程中可以有一个或者多个线程;
一个cpu运行多个线程,就是伪多线程,实际上是一个cpu在多个线程片段之间切换,只是切换的速度比较快,切换不同的线程涉及系统层面的开销;
协程(goroutine) 就是 微线程,本质是 对单一线程的优化(协程是单线程的并发)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package mainimport ( "fmt" "strconv" "time" ) func test () { for i := 1 ; i <= 10 ; i++ { fmt.Println("协程 goroutine:" + strconv.Itoa(i)) time.Sleep(time.Second * 1 ) } } func main () { go test() for i := 1 ; i <= 10 ; i++ { fmt.Println("主线程:" + strconv.Itoa(i)) time.Sleep(time.Second * 1 ) } } 主线程:1 协程 goroutine:1 协程 goroutine:2 主线程:2 主线程:3 协程 goroutine:3 主线程:4 协程 goroutine:4 协程 goroutine:5 主线程:5 协程 goroutine:6 主线程:6 主线程:7 协程 goroutine:7 协程 goroutine:8 主线程:8 协程 goroutine:9 主线程:9 协程 goroutine:10 主线程:10
主死随从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package mainimport ( "fmt" "strconv" "time" ) func test () { for i := 1 ; i <= 100 ; i++ { fmt.Println("协程 goroutine:" + strconv.Itoa(i)) time.Sleep(time.Second * 1 ) } } func main () { go test() for i := 1 ; i <= 10 ; i++ { fmt.Println("主线程:" + strconv.Itoa(i)) time.Sleep(time.Second * 1 ) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "time" ) func main () { for i := 0 ; i < 10 ; i++ { go func () { fmt.Println(i) }() } time.Sleep(time.Second * 2 ) } 10 10 10 10 10 10 10 10 6 10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "time" ) func main () { for i := 0 ; i < 10 ; i++ { go func (num int ) { fmt.Println(num) }(i) } time.Sleep(time.Second * 2 ) } 1 0 9 2 6 8 7 4 3 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "sync" ) var wg sync.WaitGroup func main () { for i := 0 ; i < 10 ; i++ { wg.Add(1 ) go func (num int ) { defer wg.Done() fmt.Println(num) }(i) } wg.Wait() } 0 9 5 6 7 8 2 1 3 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package mainimport ( "fmt" "sync" ) var num int var wg sync.WaitGroup func add () { defer wg.Done() for i := 0 ; i < 10000 ; i++ { num = num + 1 } } func sub () { defer wg.Done() for i := 0 ; i < 10000 ; i++ { num = num - 1 } } func main () { wg.Add(2 ) go add() go sub() wg.Wait() fmt.Println(num) } 1045
多个协程之间 交替执行导致了问题,协程并发争抢资源。
用 锁 可以解决上面的问题,但是不推荐,因为性能低。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 package mainimport ( "fmt" "sync" ) var num int var wg sync.WaitGroup var lock sync.Mutexfunc add () { defer wg.Done() for i := 0 ; i < 10000 ; i++ { lock.Lock() num = num + 1 lock.Unlock() } } func sub () { defer wg.Done() for i := 0 ; i < 10000 ; i++ { lock.Lock() num = num - 1 lock.Unlock() } } func main () { wg.Add(2 ) go add() go sub() wg.Wait() fmt.Println(num) }
读多写少,推荐用读写锁RWLock。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 package mainimport ( "fmt" "sync" "time" ) var num int var wg sync.WaitGroup var lock sync.RWMutexfunc add () { defer wg.Done() for i := 0 ; i < 10 ; i++ { lock.RLock() fmt.Println("开始读" ) num = num + 1 time.Sleep(time.Second * 1 ) lock.RUnlock() fmt.Println("读完了" ) } } func sub () { defer wg.Done() for i := 0 ; i < 2 ; i++ { lock.Lock() fmt.Println("开始写" ) num = num - 1 time.Sleep(time.Second * 1 ) lock.Unlock() fmt.Println("写完了" ) } } func main () { wg.Add(2 ) go add() go sub() wg.Wait() fmt.Println(num) }
管道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport "fmt" func main () { var intChan chan int intChan = make (chan int , 3 ) fmt.Printf("intChan的值是:%v \n" , intChan) intChan <- 10 num := 20 intChan <- num intChan <- 50 num1 := <-intChan num2 := <-intChan num3 := <-intChan fmt.Println(num1, num2, num3) fmt.Printf("管道实际长度:%v,管道容量是 %v" , len (intChan), cap (intChan)) }
管道关闭以后 读取可以,只是不能再写入了。如果写入超过容量,会死锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport "fmt" func main () { var intChan chan int intChan = make (chan int , 100 ) for i := 0 ; i < 10 ; i++ { intChan <- i } close (intChan) for v := range intChan { fmt.Println("value = " , v) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport ( "fmt" "sync" "time" ) func writeData (intChan chan int ) { defer wg.Done() for i := 1 ; i <= 50 ; i++ { intChan <- i fmt.Println("写入的数据为:" , i) time.Sleep(time.Second) } close (intChan) } func readData (intChan chan int ) { defer wg.Done() for v := range intChan { fmt.Println("读的数据为:" , v) time.Sleep(time.Second) } } var wg sync.WaitGroup func main () { intChan := make (chan int , 50 ) wg.Add(2 ) go writeData(intChan) go readData(intChan) wg.Wait() }
管道可以声明 只读或者只写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport ( "fmt" ) func main () { var intChan2 chan <- int intChan2 = make (chan int , 5 ) intChan2 <- 10 fmt.Println("intChan2" , intChan2) var intChan3 <-chan int if intChan3 != nil { num1 := <-intChan3 fmt.Println("num1" , num1) } intChan3 <- 20 }
有写没有读,管道就会deadlock 死锁。
但是写的快,读得慢,是不会死锁的。
select select 解决多个管道的选择问题,又叫“多路复用”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package mainimport ( "fmt" "time" ) func main () { intChan := make (chan int , 1 ) go func () { time.Sleep(time.Second * 5 ) intChan <- 10 }() stringChan := make (chan string , 1 ) go func () { time.Sleep(time.Second * 2 ) stringChan <- "msbgolang" }() select { case v := <-intChan: fmt.Println("intChan:" , v) case v := <-stringChan: fmt.Println("stringChan:" , v) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package mainimport ( "fmt" "time" ) func main () { intChan := make (chan int , 1 ) go func () { time.Sleep(time.Second * 5 ) intChan <- 10 }() stringChan := make (chan string , 1 ) go func () { time.Sleep(time.Second * 2 ) stringChan <- "msbgolang" }() select { case v := <-intChan: fmt.Println("intChan:" , v) case v := <-stringChan: fmt.Println("stringChan:" , v) default : fmt.Println("防止select被阻塞" ) } }
主动捕获异常defer+recover,来让协程出问题的时候,其它协程和主线程正常运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package mainimport ( "fmt" "time" ) func printNum () { for i := 0 ; i < 10 ; i++ { fmt.Println(i) } } func devide () { defer func () { err := recover () if err != nil { fmt.Println("devide() 出现错误:" , err) } }() num1 := 1 num2 := 0 result := num1 / num2 fmt.Println("devide:" , result) } func main () { go printNum() go devide() time.Sleep(time.Second * 4 ) }
网络
传输层:TCP 协议三次握手,四次挥手
传输层:UDP 协议(不可靠) UDP协议可能丢包;
数据切成一个一个的小数据包 发送给服务器。服务器也接收一个一个的小数据包。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport ( "fmt" "net" ) func main () { fmt.Println("客户端启动" ) conn, err := net.Dial("tcp" , "127.0.0.1:8888" ) if err != nil { fmt.Println("客户端链接失败" ) return } fmt.Println("客户端连接成功,conn:" , conn) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport ( "fmt" "net" ) func main () { fmt.Println("服务器端启动" ) listen, err := net.Listen("tcp" , "127.0.0.1:8888" ) if err != nil { fmt.Println("监听失败,err:" , err) return } conn, err2 := listen.Accept() if err2 != nil { fmt.Println("客户端等待失败,err2" , err2) return } else { fmt.Printf("连接成功,%v\n,接收到的客户端远程地址是:%v\n" , conn, conn.RemoteAddr().String()) } }
完整版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package mainimport ( "fmt" "net" "os" ) func process (conn net.Conn) { defer conn.Close() for { buf := make ([]byte , 1024 ) n, err := conn.Read(buf) if err != nil { return } if string (buf[0 :n]) == "quit\n" { fmt.Println("接收到客户端注销信号,现在执行." ) os.Exit(1 ) } fmt.Println(string (buf[0 :n])) } } func main () { fmt.Println("服务器端启动" ) listen, err := net.Listen("tcp" , "127.0.0.1:8888" ) if err != nil { fmt.Println("监听失败,err:" , err) return } for { conn, err2 := listen.Accept() if err2 != nil { fmt.Println("客户端等待失败,err2" , err2) return } else { fmt.Printf("连接成功,%v\n,接收到的客户端远程地址是:%v\n" , conn, conn.RemoteAddr().String()) } go process(conn) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package mainimport ( "bufio" "fmt" "net" "os" ) func main () { fmt.Println("客户端启动" ) conn, err := net.Dial("tcp" , "127.0.0.1:8888" ) if err != nil { fmt.Println("客户端链接失败" ) return } fmt.Println("客户端连接成功,conn:" , conn) for { reader := bufio.NewReader(os.Stdin) str, err := reader.ReadString('\n' ) if err != nil { fmt.Println("终端输入失败,err" , err) } if str == "quit\n" { _, err := conn.Write([]byte (str)) if err != nil { fmt.Println("写入失败" ) } fmt.Println("手动退出客户端" ) return } n, err := conn.Write([]byte (str)) if err != nil { fmt.Println("写入失败" ) } fmt.Printf("客户端数据发送成功,一共发送了%d字节的数据。" , n) } }
反射 放射能够 在 运行时动态获取变量信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport ( "fmt" "reflect" ) func testReflect (i interface {}) { reType := reflect.TypeOf(i) fmt.Println("reType:" , reType) reValue := reflect.ValueOf(i) fmt.Println("Value:" , reValue) num2 := 50 + reValue.Int() fmt.Println(num2) i2 := reValue.Interface() n := i2.(int ) fmt.Println(n + 10 ) } func main () { var num int = 100 testReflect(num) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package mainimport ( "fmt" "reflect" ) func testReflect (i interface {}) { reType := reflect.TypeOf(i) fmt.Println("reType:" , reType) reValue := reflect.ValueOf(i) fmt.Println("Value:" , reValue) i2 := reValue.Interface() n, flag := i2.(Student) if flag == true { fmt.Printf("名字是:%v,年龄是:%v" , n.Name, n.Age) } } type Student struct { Name string Age int } func main () { var num int = 100 testReflect(num) stu := Student{ Name: "丽丽" , Age: 18 , } testReflect(stu) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package mainimport ( "fmt" "reflect" ) func testReflect (i interface {}) { reType := reflect.TypeOf(i) fmt.Println("reType:" , reType) reValue := reflect.ValueOf(i) fmt.Println("Value:" , reValue) k1 := reType.Kind() k2 := reValue.Kind() fmt.Println(k1, k2, k1 == k2, "look this." ) i2 := reValue.Interface() n, flag := i2.(Student) if flag == true { fmt.Printf("名字是:%v,年龄是:%v" , n.Name, n.Age) fmt.Printf("\n类型是:%T" , n) } } type Student struct { Name string Age int } func main () { var num int = 100 testReflect(num) stu := Student{ Name: "丽丽" , Age: 18 , } testReflect(stu) }
通过反射修改变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package mainimport ( "fmt" "reflect" ) func testReflect (i interface {}) { reValue := reflect.ValueOf(i) fmt.Println("Value:" , reValue) reValue.Elem().SetInt(101 ) } type Student struct { Name string Age int } func main () { var num int = 100 testReflect(&num) fmt.Println(num) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 package mainimport ( "fmt" "reflect" ) type Student struct { Name string Age int } func (s Student) CPrint() { fmt.Println("调用print方法,学生名字是:" , s.Name) } func (s Student) AGetSum(n1, n2 int ) int { return n1 + n2 } func (s Student) BSet(name string , age int ) { s.Name = name s.Age = age } func TestStudentStruct (a interface {}) { val := reflect.ValueOf(a) fmt.Println(val) n1 := val.NumField() fmt.Println("结构体内部字段数为:" , n1) for i := 0 ; i < n1; i++ { fmt.Printf("第%d个字段的值是:%v\n" , i, val.Field(i)) } n2 := val.NumMethod() fmt.Println(n2) val.Method(2 ).Call(nil ) var params []reflect.Value params = append (params, reflect.ValueOf(10 )) params = append (params, reflect.ValueOf(20 )) result := val.Method(0 ).Call(params) fmt.Println("返回值是:" , result[0 ], result) } func main () { s := Student{ Name: "丽丽" , Age: 18 , } TestStudentStruct(s) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package mainimport ( "fmt" "reflect" ) type Student struct { Name string Age int } func (s Student) CPrint() { fmt.Println("调用print方法,学生名字是:" , s.Name) } func (s Student) AGetSum(n1, n2 int ) int { return n1 + n2 } func (s Student) BSet(name string , age int ) { s.Name = name s.Age = age } func TestStudentStruct (a interface {}) { val := reflect.ValueOf(a) fmt.Println(val) n := val.Elem().NumField() fmt.Println(n) val.Elem().Field(0 ).SetString("张三" ) } func main () { s := Student{ Name: "丽丽" , Age: 18 , } TestStudentStruct(&s) fmt.Println(s) }
协程管道练习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package mainimport ( "fmt" ) var intChan chan int = make (chan int , 10000 )func main () { var printChan chan int = make (chan int , 10000 ) var exitChan chan bool = make (chan bool , 8 ) go initChan(10000 ) for i := 0 ; i <= 8 ; i++ { go isPrime(intChan, printChan, exitChan) } go func () { for i := 0 ; i < 8 ; i++ { <-exitChan } close (printChan) }() for { res, ok := <-printChan if !ok { break } fmt.Println("素数是:" , res) } } func initChan (num int ) { for i := 1 ; i < num; i++ { intChan <- i } close (intChan) } func isPrime (intChan chan int , printChan chan int , exitChan chan bool ) { var flag bool for { num, ok := <-intChan flag = true if !ok { break } for j := 2 ; j < num; j++ { if num%j == 0 { flag = false continue } } if flag { printChan <- num } } exitChan <- true }
label 和 select 管道 管道写完都要 close,不然读的时候可能会死锁错误,如果不想总是用这个 锁,”每次操作管道”都要使用 label 配合 select 选择管道,select 的default 返回值 赋值给了label。
label: for {select {case := <-chanName: case := <-chanName2: default returnValue }}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package mainimport ( "fmt" ) var intChan chan int = make (chan int , 10000 )func main () { var printChan chan int = make (chan int , 10000 ) var exitChan chan bool = make (chan bool , 8 ) go initChan(10000 ) for i := 0 ; i <= 8 ; i++ { go isPrime(intChan, printChan, exitChan) } go func () { for i := 0 ; i < 8 ; i++ { <-exitChan } }() label: for { select { case res := <-printChan: fmt.Println("素数是:" , res) default : break label } } } func initChan (num int ) { for i := 1 ; i < num; i++ { intChan <- i } close (intChan) } func isPrime (intChan chan int , printChan chan int , exitChan chan bool ) { var flag bool label: for { select { case num := <-intChan: flag = true for j := 2 ; j < num; j++ { if num%j == 0 { flag = false continue } } if flag { printChan <- num } default : break label } } fmt.Println("协程已经结束" ) exitChan <- true }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package mainimport ( "fmt" "strconv" "time" ) func main () { fmt.Println() storageChan := make (chan Product, 100 ) shopChan := make (chan Product, 100 ) exitChan := make (chan bool , 1 ) for i := 0 ; i < 9 ; i++ { go Producer(storageChan, 10 ) } go Logistics(storageChan, shopChan) go Consumer(shopChan, 10 , exitChan) if <-exitChan { return } } type Product struct { Name string } func Producer (storageChan chan <- Product, count int ) { for { producer := Product{"商品:" + strconv.Itoa(count)} storageChan <- producer time.Sleep(time.Second) count-- fmt.Println("生产了," , producer) if count < 1 { return } } } func Logistics (storageChan <-chan Product, shopChan chan <- Product) { for { product := <-storageChan shopChan <- product fmt.Println("运输了," , product) } } func Consumer (shopChan <-chan Product, count int , exitChan chan <- bool ) { for { product := <-shopChan fmt.Println("消费了," , product) count-- if count < 1 { exitChan <- true return } } }
管道定时任务应用 第一类:定时任务,类似延时消息队列。
第二类:周期性执行某个任务,类似定期同步某些数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package mainimport ( "fmt" "math/rand" "time" ) var flag bool = isStopTimer()func main () { fmt.Println("当前时间" , time.Now()) timer := time.NewTicker(time.Second * 3 ) if flag { timer.Stop() } else { t := <-timer.C fmt.Println(t) } } func isStopTimer () bool { rand.Seed(time.Now().UnixNano()) tempInt := rand.Intn(2 ) + 18 if tempInt >= 18 { fmt.Println("已经找到了大于18,结束。" ) return true } else { return false } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package mainimport ( "fmt" "time" ) func main () { var count int = 0 ticker := time.NewTicker(time.Second * 1 ) go func () { for { t := <-ticker.C fmt.Println("时间:" , t.Format("2003-01-02 03:04:05PM" )) count++ if count > 3 { ticker.Stop() } } }() time.Sleep(time.Second * 10 ) fmt.Println("游戏结束" ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package mainimport ( "fmt" "sync" "time" ) func main () { var count int = 0 var waitGroup sync.WaitGroup waitGroup.Add(1 ) ticker := time.NewTicker(time.Second * 1 ) go func () { defer ticker.Stop() defer waitGroup.Done() for { t := <-ticker.C fmt.Println("时间:" , t.Format("2003-01-02 03:04:05PM" )) count++ if count > 3 { return } } }() time.Sleep(time.Second * 5 ) waitGroup.Wait() fmt.Println("游戏结束" ) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package mainimport ( "fmt" "sync" "time" ) func main () { var count int = 0 var waitGroup sync.WaitGroup waitGroup.Add(1 ) ticker := time.NewTicker(time.Second * 1 ) go func () { defer ticker.Stop() defer waitGroup.Done() for { t := <-ticker.C fmt.Println("ticker 时间:" , t.Format("2003-01-02 03:04:05PM" )) count++ if count > 2 { return } } }() var countA int = 0 timer := time.NewTimer(time.Second * 1 ) go func () { defer timer.Stop() defer waitGroup.Done() for { t := <-ticker.C fmt.Println("timer 时间:" , t.Format("2003-01-02 03:04:05PM" )) timer.Reset(time.Second) countA++ if countA > 3 { return } } }() time.Sleep(time.Second * 5 ) waitGroup.Wait() fmt.Println("游戏结束" ) }