1.认识Golang代码特性
- package main //1.包含main函数的文件就是一个main包--当前程序的包名
- // import "fmt"
- // import "time"
- import(
- "fmt"
- "time"
- )//3.同时包含多个包 4.强制代码风格:函数的 { 一定和函数名在同一行,否则会出现语法错误
- //main函数
- func main() {
- fmt.Println("hello Go!")
- // fmt.Println("hello Go!"); 2.加不加分号都可以,建议不加分号
- time.Sleep(1 * time.Second)
- }
复制代码 2.Golang变量声明的四种方式
- package main
- import (
- "fmt"
- )
- func main() {
- //方法一:声明一个变量,不初始化默认是0
- var a int
- fmt.Println("a =",a)
- fmt.Printf("type of a = %T\n",a)
- //方法二:声明一个变量,初始化
- var b int = 100
- fmt.Println("b =",b)
- fmt.Printf("type of b = %T\n",b)
- var bb string = "abcd"
- fmt.Printf("bb = %s,type of bb = %T\n",bb,bb)
- //方法三:在初始化时可以省去数据类型,通过值自动匹配当前的变量的数据类型
- var c = 100
- fmt.Println("c =",c)
- fmt.Printf("type of c = %T\n",c)
- var cc = "abcd"
- fmt.Printf("cc = %s,type of cc = %T\n",cc,cc)
- //方法四:(常用的方法)省去var的关键字,直接:=自动匹配;在声明的变量是全局变量时,方法四是不可用的会报错
- e := 100
- fmt.Println("e =",e)
- fmt.Printf("type of e = %T\n",e)
- ee := "abcd"
- fmt.Printf("ee = %s,type of ee = %T\n",ee,ee)
- eee := 3.14
- fmt.Printf("eee = %s,type of eee = %T\n",eee,eee)
- //声明多个变量
- var xx,yy int = 100,200 //相同数据类型
- fmt.Println("xx =",xx," yy =",yy)
- var mm,nn = 100,"abcd" //不同数据类型
- fmt.Println("mm =",mm," nn =",nn)
- //多行的多变量声明
- var (
- vv int = 100
- jj bool = true
- )
- fmt.Println("vv =",vv," jj =",jj)
- }
复制代码 3.常量与iota
- package main
- //const 来定义枚举类型
- const (
- //可以在const()添加一个关键字 iota,每行的iota都会累加1,第一行的iota的默认值是0
- BEIJING = iota //iota = 0
- SHANGHAI //iota = 1
- SHENZHEN //iota = 2
- )
- //iota只能出现在const的括号中
- const (
- a,b = iota+1,iota+2// 0+1,0+2
- c,d // 1+1,1+2
- e,f // 2+1,2+2
- g,h = iota*2,iota*3// 3*2,3*3
- i,k // 4*2,4*3
- )
- func main()
- {
- //常量-具有只读属性
- const length int = 10
- fmt.Println("length = ",length)
- length = 100 //报错-常量不可更改
- }
复制代码 4.Golang多返回值的三种写法
- package main
- import "fmt"
- func fool(a string,b int) int {
- fmt.Println("a = ",a)
- fmt.Println("b = ",b)
- c := 100
- return c
- }
- //1.返回多个返回值-匿名
- func foo2(a string,b int) (int,int) {
- fmt.Println("a = ",a)
- fmt.Println("b = ",b)
- return 666,777
- }
- //2.返回多个返回值-有形参名称
- func foo3(a string,b int) (r1 int,r2 int) {
- fmt.Println("------------foo3-----------")
- fmt.Println("a = ",a)
- fmt.Println("b = ",b)
- r1 = 1000
- r2 = 2000
- return r1,r2
- //return; 方法3--也可以返回r1,r2
- }
- func main() {
- c := fool("abc",555)
- fmt.Println("c = ",c)
- ret1,ret2 := foo2("bfr",666)
- fmt.Println("ret1 = ",ret1,"ret2 = ",ret2)
- ret3,ret4 := foo3("grx",777)
- fmt.Println("ret3 = ",ret3,"ret4 = ",ret4)
- }
复制代码 5.init函数与import导包
递归式导包直到末了一个包没有依赖包->加载该包全局的常量变量->执行init函数
"主程序开始之前,加载一些配置文件、加载一些数据库的内容、根本环境变量的初始化"
- package main
- import(
- "GolangStudy/Golang_5/lib1"
- "GolangStudy/Golang_5/lib2"
- )
- func main(){
- lib1.LibTest()
- lib2.LibTest()
- }
复制代码- package lib1
- import "fmt"
- //API接口
- func LibTest() {
- fmt.Println("Lib1Test.....")
- }
- //init初始化函数
- func init() {
- fmt.Println("Lib1init.....")
- }
复制代码- package lib2
- import "fmt"
- //API接口--大写首字母表示对外开放该接口
- func LibTest() {
- fmt.Println("Lib2Test.....")
- }
- //init初始化函数
- func init() {
- fmt.Println("Lib2init.....")
- }
复制代码 运行结果:
三种导包的方式:
- //三种导包的方式
- import(
- _ "GolangStudy/Golang_5/lib1" //_表示匿名,可以在不使用该包但是可以调用它的init函数-无法使用当钱包的方法
- //mylib "GolangStudy/Golang_5/lib2" //给包起别名mylib
- . "GolangStudy/Golang_5/lib2" // . 表示将该包直接导入main包直接使用
- )
- func main(){
- //lib1.LibTest()
- //lib2.LibTest()
- //mylib.LibTest()
- LibTest()//同名方法容易导致歧义
- }
复制代码 6.Golang中指针的利用
- package main
- import "fmt"
- func swap(pa *int, pb *int) {
- var tem int;
- tem = *pa
- *pa = *pb
- *pb = tem
- }
- func main() {
- var a int = 10
- var b int = 20
- swap(&a,&b)
- fmt.Println("a = ",a,"b = ",b)
- var p *int
- p = &a
- fmt.Println("p = ",p)
- var pp **int = &p
- fmt.Println("pp = ",pp)
- }
复制代码 7.Golang中的defer语句
- package main
- import "fmt"
- func main(){
- //写入defer关键字--类似C++中的析构函数--出它作用域时会调用
- defer fmt.Println("main end1")//先入栈
- defer fmt.Println("main end2")//再入栈
- fmt.Println("main run1")
- fmt.Println("main run2")
- }
复制代码 输出结果:
defer和return的执行顺序
- func deferFunc() int{
- fmt.Println("defer func called...")
- return 0
- }
- func returnFunc() int{
- fmt.Println("return func called...")
- return 0
- }
- func rad() int {
- defer deferFunc()
- return returnFunc()
- }
- func main() {
- rad()
- }
复制代码 输出结果: return比defer先执行
8.Golang中的数组
—静态数组
静态数组传参是值拷贝传参,并且只能吸取特定格式的数组确定元素类型与元素个数
- package main
- import "fmt"
- //值拷贝传参,将实参数组拷贝给形参
- func printArray(myArray [10]int) { //只能接收1、2即int[10]数据类型
- for index,value:=range myArray {
- fmt.println(index," ",value)
- }
- }
- func printArray(myArray [4]int) { 只能接收3即int[4]数据类型
- for index,value:=range myArray {
- fmt.println(index," ",value)
- }
- }
- func main(){
- //固定长度的数组
- var myArray1 [10]int
- myArray2 := [10]int{1,2,3,4}
- myArray3 := [4]int{1,2,3,4}
- //for i:= 0; i<10; i++
- for i:=0; i<len(myArray1); i++{
- fmt.println(myArray1[i])
- }
- for index,value:=range myArray1 {
- fmt.println(index," ",value)
- }
- //查看数组的数据类型
- fmt.printf("myArray1 types = %T\n",myArray1)
- fmt.printf("myArray2 types = %T\n",myArray2)
- fmt.printf("myArray3 types = %T\n",myArray3)
- }
复制代码 —动态数组(slice切片)
- package main
- import "fmt"
- //动态数组具有传参上的优势
- //传递的是当前数组的指针首地址,引用传递
- func printArray(myArray []int) {
- // _ 表示匿名的变量
- for _, value := range myArray {//不关心下标,但必须用两个接收
- fmt.Println("value = ",value)
- }
- myArray[0] = 100
- }
- func main() {
- myArray := []int{1,2,3,4} //动态数组,切片 slice
- fmt.Printf("myArray type is %T\n",myArray)//输出:myArray type is []int
- printArray(myArray)
- for _, value := range myArray {
- fmt.Println("value = ",value)
- }
- }
复制代码 —四种声明一个切片的方式
- func main () {
- //声明slice是一个切片,并且初始化,默认值是1,2,3;长度len是3
- slice := []int{1,2,3}
-
- //声明slice1是一个切片,但没有给它分配空间
- var slice1 []int //此时长度就是0
- slice1 = make([]int,3)//通过make给slice1分配空间,默认值是0
- //声明slice2是一个切片,同时通过make给slice2分配空间,默认值是0
- var slice2 []int = make([]int,3)
- //声明slice3是一个切片,同时分配空间,通过:=推导出slice是一个切片
- slice := make([]int,3)
- fmt.Printf("len = %d,slice = %v\n",len(slice1),slice1)
- //判断一个slice是否为0
- if slice == nil {
- fmt.printf("slice是一个空切片")
- }else{
- fmt.printf("slice不是一个空切片")
- }
- }
复制代码 —切片容量的追加
- func main () {
- var numbers = make([]int,3,5)//开辟五个空间只初始化3个为0
- fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
- //向numbers切片追加一个1
- numbers = append(numbers,1)
- fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
- numbers = append(numbers,2)
- fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
- numbers = append(numbers,3)//会进行2倍扩容
- fmt.Printf("len = %d,cap = %d,numbers = %v\n",len(numbers),cap(numbers),numbers)
- var numbers2 = make([]int,3)//开辟三个空间并全部初始化为0
- fmt.Printf("len = %d,cap = %d,numbers2 = %v\n",len(numbers2),cap(numbers2),numbers2)
- numbers2 = append(numbers2,1)//会进行2倍扩容
- fmt.Printf("len = %d,cap = %d,numbers2 = %v\n",len(numbers2),cap(numbers2),numbers2)
- }
复制代码 输出结果:
—切片的截取
- func main () {
- s := []int{1,2,3} //len=3,cap=3
- //[0,2)
- s1 := s[0:2] //取1和2,前面省略表示从第0个开始取,后面省略表示取到最后一个
- fmt.Println(s1)
-
- s1[0] = 100
- fmt.Println(s1) //s1此时也指向s的第一个,相当于浅拷贝
- fmt.Println(s)
- //copy深拷贝,将底层数组的slice一起进行拷贝
- s2 := make([]int,2) //s2 = [0,0,0]
- copy(s2,s1)
- fmt.Println(s2) //可以先将s切片成s1,再进行深拷贝给s2,就可以分离
- }
复制代码 9.Golang中基于哈希的Map
—Map的三种声明界说方式
- func main() {
- //第一种声明方式
- var myMap1 map[string]string //仅仅是声明,没有实际的空间,并不能被使用
- if myMap1 == nil {
- fmt.Println("myMap1是一个空map")
- }
- myMap1 = make(map[string]string,10) //用make给Map开辟十个键值对的空间
- myMap1["one"] = "java"
- myMap1["two"] = "C++"
- myMap1["three"] = "python"
- //...当插入十个之后也会二倍扩容
- fmt.Println(myMap1)//打印出来是无序的
- //第二种声明方式
- myMap2 := make(map[int]string)
- myMap2[1] = "java"
- myMap2[2] = "C++"
- myMap2[3] = "python"
- fmt.Println(myMap2)
- //第三种声明方式
- myMap3 := map[int]string {
- 4 : "java",
- 5 : "C++",
- 6 : "python",
- }
- fmt.Println(myMap3)
- }
复制代码 —Map的根本利用
- func printMap(cityMap map[string]string) {
- for key,value := range cityMap {
- fmt.Printf("key = %s ",key)
- fmt.Printf("value = %s\n",value)
- }
- cityMap["one"] = "golang"
- }
- //指向当前map内存结构体地址的指针cityMap
- func main() {
- cityMap := make(map[string]string,3)
- //添加
- cityMap["one"] = "java"
- cityMap["two"] = "C++"
- cityMap["three"] = "python"
- //删除
- delete(cityMap,"three")
- //修改
- cityMap["two"] = "php"
- //传参
- printMap(cityMap)
- //遍历
- for key,value := range cityMap {
- fmt.Printf("key = %s ",key)
- fmt.Printf("value = %s\n",value)
- }
- }
- //将一个map赋值给另一个时只能完成指针之间的浅拷贝,只能通过make开辟一个Map进行遍历赋值
复制代码 10.struct(类)的界说和利用
—struct类的界说
- //声明一种行的数据类型,是Int的一个别名
- type myint int
- type Book struct {
- title string
- auth string
- }
- func changeBook(book Book) {
- //传递book的一个副本
- book.auth = "666"
- }
- func changeBook2(book *Book) {
- //传递指向Book结构体的指针
- book.auth = "777"
- }
- func main() {
- // var a myint = 10
- // fmt.Printf("type = %T",a)
- var book1 Book
- book1.title = "Golang"
- book1.auth = "zhang3"
- fmt.Printf("book1 = %v",book1)
- }
复制代码 —类的封装和方法的调用
- //go语言中的类实际上是通过结构体来绑定方法
- package main
- //方法名、类名如果首字母大写,其它包也可以访问
- type Hero struct {
- Name string
- Ad int
- Level int
- }
- //当前括号表示该方法绑定到了Hero结构体,this表示调用对象,谁调用该方法this就指哪个对象
- func (this Hero) GetName() string{
- return this.Name
- }
- //this是当前调用对象的一个副本
- func (this Hero) SetName(newName string) {
- this.Name = newName
- }
- //此时this就是指向当前对象的指针,就可以修改了
- func (this *Hero) SetName(newName string) {
- this.Name = newName
- }
- func main() {
- //创建一个对象
- hero := Hero{Name: "zhang3",Ad: 100,Level: 1}
- }
复制代码 —继承的根本语法
- type Human struct {
- name string
- sex string
- }
- func (this *Human) Eat() {
- fmt.Println("human Eat().....")
- }
- func (this *Human) Walk() {
- fmt.Println("human Walk().....")
- }
- type SuperMan struct {//Go中实际是以组合的形式实现继承
- Human //Superman继承了Human类的所有方法
- level int
- }
- //重写(覆盖)父类方法
- func (this *SuperMan) Eat() {
- fmt.Println("SuperMan Eat().....")
- }
- //子类的新方法
- func (this *SuperMan) Fly() {
- fmt.Println("SuperMan Fly().....")
- }
- func main() {
- h := Human{"zhang3","female"}
- h.Eat()
- h.Walk
- s := SuperMan{Human{"li4","female"},88}
- // var s SuperMan
- // s.name = "li4"//...
- s.Walk() //子类调用父类的方法
- s.Eat() //子类调用子类重写的方法
- s.Fly() //子类调用子类的新方法
- }
复制代码 —interface实现多态
- package main
- //面向对象的多态:定义一个接口完成多态的现象;接口定义抽象方法,子类去继承实现重写这个方法
- //interface本质上是一个指针,指向当前类型包含的函数列表
- type AnimalIF interface {
- Sleep()
- GetColor() string //获取动物的颜色
- GetType() string //获取动物的类型
- }
- //具体的值--要继承AnimalIF interface只需要将他的三个方法实现,不需要显式继承
- type Cat struct {
- color string //猫的颜色
- }
- func (this *Cat) Sleep() {
- fmt.Println("cat is sleep")
- }
- func (this *Cat) GetColor() string {
- return this.color
- }
- func (this *Cat) GetType() string {
- return "cat"
- }
- //具体的值--狗
- type Dog struct {
- color string
- }
- func (this *Dog) Sleep() {
- fmt.Println("Dog is sleep")
- }
- func (this *Dog) GetColor() string {
- return this.color
- }
- func (this *Dog) GetType() string {
- return "Dog"
- }
- func showAnimal(animal AnimalIF)//调用该函数,形参为父类指针,实参为子类对象实现多态
- {
- animal.Sleep()
- }
- func main() {
- // var animal AnimalIF //接口的数据类型,相当于定义了一个父类指针
- // animal = &Cat("green") //让父类的指针指向一个子类对象
- // animal.Sleep() //指向子类对象的父类指针调用子类方法实现多态
- cat := Cat("green")
- dog := Dog("yellow")
- showAnimal()
- }
复制代码 —interface{}空接口万能类型
- //interface{} 空接口,万能类型-》可以引用任意数据类型
- package main
- import "fmt"
- func myFunc(arg interface{}) { //可以传任意类型的实参
- fmt.Println("myFunc is called..")
- fmt.Println(arg)
- //类型断言
- value,ok := arg.(string) //value是数据值,ok是error
- if !ok {
- fmt.Println("arg is not a string")
- }else{
- fmt.Println("arg is a string")
- }
- fmt.Println(value)
- }
- type Book struct {
- auth string
- }
- func main() {
- book := Book{"Golang"}
- myFunc(book)
- myFunc("abcd")
- myFunc(888)
- myFunc(23.45)
- }
复制代码 11.Golang中反射的概念
—接口type interface { }的类型
Golang中一个变量包含一个pair即type和value对。
type分为static type(在编译时就确定并且不会改变)和concrete type(在运行时确定并且会改变)。
- var i int // static type 为 int;
- var i interface{} // pair()
- i = 18 // concrete type 为 int
- i = "Go编程时光" // concrete type 变为 string
复制代码- type Reader interface {
- ReadBook()
- }
- type Writer interface {
- WriteBook()
- }
- //具体类型
- type Book struct {
- }
- func (this *Book) ReadBook() {
- fmt.Println("Read a book.")
- }
- func (this *Book) WriteBook() {
- fmt.Println("Write a book.")
- }
- func main() {
- b := &Book{} //type:*Book value:0xc000012028
- var r Reader //concrete type:nil,static type:Reader value:nil
- r = b //concrete type:Book*,static type Reader value:0xc000012028
- r.ReadBook() //Reader - Book* 多态
- var w Writer //concrete type:nil,static type:Writer value:nil
- w = r.(Writer)//类型断言,检查r是否实现了Writer,并将Book*给w
- w.WriteBook()
- }
复制代码 —reflect.ValueOf 和 reflect.TypeOf
- package main
- import "fmt"
- import "reflect"
- type User struct {
- Id int//一个filed
- Name string//第二个filed
- Age int //第三个filed
- }
- func (this *User) Call() {
- fmt.Println("User is called ...")
- fmt.Println("%v\n",this)
- }
- func main() {
- user := User{1,"bfr",18}
- DoF(user)
- }
- func DoF(input interface{}) {
- //获取input的type
- inputType := reflect.TypeOf(input)
- fmt.Println("inputType :",inputType.Name())//?直接打印出当前类型的名称?
- //获取input的value
- inputValue := reflect.ValueOf(input)
- fmt.Println("inputValue :",inputValue)
- //通过type获取里面重要字段
- //通过inputType可以获取NumFiled,进行遍历,就能得到每个filed
- for i := 0;i < inputType.NumField(); i++ {
- field := inputType.Field(i)
- value := inputValue.Field(i).Interface()//?获取字段的值
- fmt.Printf("%s: %v = %v\n",field.Name,field.Type,value)//ID,int,1
- }
- //通过Type获取里面的方法,调用
- for i:=0; i<inputType.NumMethod(); i++ { //遍历User有多少个方法
- m := inputType.Method(i)
- fmt.Printf("%s: %v\n",m.Name,m.Type)
- }
- }
复制代码
12.结构体标签
- package main
- import "fmt"
- import "reflect"
- //在不同包中有不同的解释说明
- type resume struct {
- Name string `info:"name" doc:"我的名字"`
- Sex string `info:"sex"`
- }
- func findTag(str interface{}) {
- t := reflect.TypeOf(str).Elem()//Elem当前结构体的全部元素
- for i := 0; i < t.NumField(); i++ {
- taginfo := t.Field(i).Tag.Get("info")
- tagdoc := t.Field(i).Tag.Get("doc")
- fmt.Println("info: ",taginfo," dac:",tagdoc)
- }
- }
- func main() {
- var res resume
- findTag(&res)
- }
复制代码- //结构体标签-key已知,value未知
- type Movie struct {
- Title string `json:"title"` //在json中显示的字段
- Year int `json:"year"`
- Price int `json:"price"`
- Actors []string `json:"actors"`
- }
- func main() {
- movie := Movie{"喜剧之王",2000,10,[]string{"xingye","zbz"}}
-
- //编码的过程 将结构体->json
- jsonStr,err := json.Marshal(movie)//Marshal可以将结构体转化为json格式
- if err != nil {
- fmt.Println("json marshal error",err)
- }else{
- fmt.Printf("josnStr = %s\n",jsonStr)
- }
- //解码的过程 json->结构体
- myMovie := Movie{}
- err = json.Unmarshal(jsonStr,&myMovie)//将json字符串解析给myMovie结构体
- if err != nil {
- fmt.Println("json unmarshal error",err)
- return
- }
- }
复制代码 13.Golang中的协程:goroutine
—协程的演变发展
—单进程的操纵系统只能顺序执行任务,一旦某个任务壅闭,别的任务都不能处置惩罚。
—多进程/多线程解决了,CPU调度器进行轮询调度切换进程/线程 ,当某个时间片到了就会切换。但是进程/线程间切换具有成本,一旦数量过大,CPU的利用服从就会大大降低。进程占4GB左右,线程占用4MB左右,也有高内存占用的毛病。
—将一个线程拆分,一半在用户层面供用户调用(协程:co-routine),一半在内核层供CPU调度。
—N : 1,如果有一个协程壅闭,那它的下一个协程就会受到影响。操纵系统感知不到用户级协程的存在,无法将壅闭的协程与线程分离,线程资源被完全占用
—M : N,利用多核,一个CPU绑定多个线程;解决了某个协程壅闭影响别的协程的问题;通过优化写成调度器优化服从,CPU不做调度。
—Golang对协程的处置惩罚
co-routine -> goroutine;将占用内存优化到KB单元(可以大量生产),(可以机动调度)。
—通过优化调度器实现机动调度
- package main
- import "fmt"
- import "time"
- func newTask() {
- i:=0
- for {
- i++
- fmt.Printf("new Goroutine : i = %d\n",i)
- time.Sleep(1 * time.Second)
- }
- }
- func main() {
- //创建一个go程 去执行newTask()流程
- go newTask()
- time.Sleep(10*time.Second)
- fmt.Println("main goroutine exit")
- // i:=0
- // for { //死循环main
- // i++
- // fmt.Printf("main goruntine: i = %d\n",i)
- // time.Sleep(1*time.Second)
- // }
- }
复制代码- package main
- import "fmt"
- import "time"
- import "runtime"
- func main() {
- //调匿名无参goroutine
- go func() {//匿名方法,直接用Go承载一个形参为空返回值为空的一个函数
- defer fmt.Println("A.defer")
- func() {//仅仅是函数定义
- defer fmt.Println("B.defer")
- //return
- runtime.Goexit()
- fmt.Println("B")
- }()
- fmt.Println("A")
- }()//调用
- //调匿名有参goroutine
- go func(a int,b int) bool { //并不是阻塞操作,是一个异步操作,不能拿到返回值
- fmt.Println("a = ",a," b = ",b)
- return true
- }(10,20)
- time.Sleep(1*time.Second)
- }
复制代码 14.channel-go语言中协程间通讯的机制
—构成死锁:
1.无缓存channel、只写不读或只读不写、导致主线程壅闭。
2.有缓存channel、已满只写不读或为空只读不写、导致主线程壅闭。
- package main
- import "fmt"
- //import "time"
- func main() {
- c := make(chan int,3)//带有缓冲的channel
- fmt.Println("len(c) = ",len(c)," cap(c) = ",cap(c))
- go func() {
- defer fmt.Println("子go程结束")
- for i:=0;i<6;i++{
- c <- i
- fmt.Println("running...:","i = ",i," len(c) = ",len(c)," cap(c) = ",cap(c))
- }
- }()
- //time.Sleep(2 * time.Second)
- // for i:=0;i<2;i++ {
- // num := <-c //从c中接收数据,并赋值给num
- // fmt.Println("num =",num)
- // }
-
- fmt.Println("main 结束")
- }
复制代码 —close关闭channel
关闭channel后,无法向channel再发送数据(再发会引发 panic 错误后导致吸取立刻返回零值)
关闭channel后,仍旧具有缓存,等读端读完了才会返回。
简朴var声明一个channel数据类型,没有进行make,称为nil channel。无论收发都会壅闭。
- package main
- import "fmt"
- func main() {
- c := make(chan int)
- go func() {
- for i:=0;i<5;i++ {
- c <- i
- }
- //close可以关闭一个channel
- close(c)
- }()
- for {
- //ok=true表示channel没有关闭
- if data,ok := <-c; ok { //原子性操作:确保通道接收与状态检查在同一个代码块中完成
- fmt.Println(data)
- }else{
- break
- }
- }
- fmt.Println("Main Finished..")
- }
复制代码 —channel 和 range
实验从c中读数据,range会壅闭等待这个结果;c中有数据range就会返回并进入本轮for循环,没有数据就会壅闭
- //可以使用range来迭代不断操作channel
- for data := range c {
- fmt.Println(data)
- }
复制代码 —channel 和 select
单流体下的一个go只能监视一个channel状态,壅闭监听,select可以解决一个go监听多个channel状态,如果某个channel可读或可写它就会立刻返回。一般会循环进行select监控多个channel。
- package main
- import "fmt"
- func fibo(c,quit chan int){
- x,y := 1,1 //1,1->1; 1,2->1;
- for{
- select{
- case c <- x: //只要func可读这边就可写
- //如果c可写,则该case就会进来
- t := x
- x = y
- y = t+y
- case <-quit: //只要quit被写入这边就可读就退出
- fmt.Println("quit")
- return
- }
- }
- }
- func main() {
- c := make(chan int)
- quit := make(chan int)
- go func() {
- for i := 0; i < 6; i++{
- fmt.Println(<-c)//读c
- }
- quit <- 0 //循环结束退出
- }()
- //main go
- fibo(c,quit)
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |