浅析Go语言中Channel的各种用法

目录
  • Go语言基础四
    • if定义
    • 单层if语法格式
    • 语法警告
    • 多层if语法格式
    • Switch定义
    • Type Switch
    • Select定义
    • Select语句注意事项
    • Select用法补充
    • 退出
    • 判断Channel状态

Go语言基础四

今天我们要来学习if语句,也就是大家口中的判断语句,我们首先来看一下if语句的定义

if定义

条件语句需要开发者通过指定一个或多个条件并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句。相信读者看到这儿,也是云里雾里的感觉,我们怎么来表示truefalse呢?

单层if语法格式

  • 可省略条件表达式括号。
  • 持初始化语句,可定义代码块局部变量。
  • 代码块左 括号必须在条件表达式尾部。

if 布尔表达式 {
    /* 在布尔表达式为 true 时执行 */
    }

这里要为读者介绍的是,如果if后面的条件语句程序给出的数能够满足,则我们表示为true;如果不能,则返回false

package main
​
import "fmt"
​
func main() {
   a := 3
   if a > 2 {
      fmt.Println("true")
   } else {
      fmt.Println("false")
   }
}

如代码块所示,这里我们定义了一个变量a的值为3,接下来是一个if判断,如果该数值>2,则调用函数打印输出true;否则返回false。换句话说,我们这里即是对a变量的一个判断,至于调用函数打印输出的内容,由读者自行决定

语法警告

在Go语法中,不支持三元操作符(三目运算符) a > b ? a : b,如果读者对三元运算符较感兴趣,可以移步至java了解三元运算符(其本质上也是一种if判断形式

package main
​
import "fmt"
​
func main() {
   /* 定义局部变量 */
   var a int = 10
   /* 使用 if 语句判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" )
   }
   fmt.Printf("a 的值为 : %d\n", a)
}  

上方是关于if判断的一个小练习,读者自行体会即可;if 在布尔表达式为 true 时,其后紧跟的语句块执行,如果为 false 则执行 else 语句块。

package main
import "fmt"
func main() {
   /* 局部变量定义 */
   var a int = 100
   /* 判断布尔表达式 */
   if a < 20 {
       /* 如果条件为 true 则执行以下语句 */
       fmt.Printf("a 小于 20\n" )
   } else {
       /* 如果条件为 false 则执行以下语句 */
       fmt.Printf("a 不小于 20\n" )
   }
   fmt.Printf("a 的值为 : %d\n", a)
}

Go语言中,if语句也支持嵌套处理,即可以实现多重if判断以达到程序想要的结果

多层if语法格式

if 布尔表达式 1 {
   /* 在布尔表达式 1 为 true 时执行 */
   if 布尔表达式 2 {
      /* 在布尔表达式 2 为 true 时执行 */
   }
}

package main
​
import "fmt"
​
func main() {
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
   /* 判断条件 */
   if a == 100 {
       /* if 条件语句为 true 执行 */
       if b == 200 {
          /* if 条件语句为 true 执行 */
          fmt.Printf("a 的值为 100 , b 的值为 200\n" )
       }
   }
   fmt.Printf("a 值为 : %d\n", a )
   fmt.Printf("b 值为 : %d\n", b )
}     

如上图所示,我们在if语句里面嵌套了另一个if语句,即是在默认a == 100的情况下写出对变量b的值的判断,最终调用函数打印输出a和b的值

有时候我们多个变量匹配同一个值,就会用到Switch语句

Switch定义

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上直下逐一测试,直到匹配为止。Golang switch 分支表达式可以是任意类型,不限于常量。可省略 break,默认自动终止。

Switch语法格式

switch var1 {
    case val1:
        ...
    case val2:
        ...
    default:
        ...
}
package main
import "fmt"
func main() {
   /* 定义局部变量 */
   var grade string = "B"
   var marks int = 90
​
   switch marks {
      case 90: grade = "A"
      case 80: grade = "B"
      case 50,60,70 : grade = "C"
      default: grade = "D"
   }
​
   switch {
      case grade == "A" :
         fmt.Printf("优秀!\n" )
      case grade == "B", grade == "C" :
         fmt.Printf("良好\n" )
      case grade == "D" :
         fmt.Printf("及格\n" )
      case grade == "F":
         fmt.Printf("不及格\n" )
      default:
         fmt.Printf("差\n" )
   }
   fmt.Printf("你的等级是 %s\n", grade )
}    

由上方代码块可知,我们定义了两个局部变量grademarks,对marks进行Switch判断操作,当case满足不同的值的时候,调用函数打印输出的值也不一样

Type Switch

switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型

Type Switch语法格式

switch x.(type){
    case type:
       statement(s)
    case type:
       statement(s)
    /* 你可以定义任意个数的case */
    default: /* 可选 */
       statement(s)
} 

由于Type Switch用途不是特别的多,作者在这里不作详细描述,读者可以去官网自行查询相关文档进行学习

Select定义

  • select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。
  • selectGo中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收
  • select 随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的

Select语法格式

select {
    case communication clause  :
       statement(s);
    case communication clause  :
       statement(s);
    /* 你可以定义任意数量的 case */
    default : /* 可选 */
       statement(s);
} 

Select语句注意事项

  • 每个case必须是一个通信
  • 所有channel表达式都会被求值
  • 所有被发送的表达式都会被求值
  • 如果任意某个通信可以进行,它就执行;其他被忽略
  • 如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。
  • 如果有default子句,则执行该语句。
  • 如果没有default字句,select阻塞,直到某个通信可以运行;Go不会重新对channel值重新进行求值。
package main
​
import "fmt"
​
func main() {
   var c1, c2, c3 chan int //通道机制
   var i1, i2 int
   select {
   case i1 = <-c1:
      fmt.Printf("received ", i1, " from c1\n")
   case c2 <- i2:
      fmt.Printf("sent ", i2, " to c2\n")
   case i3, ok := (<-c3): // same as: i3, ok := <-c3
      if ok {
         fmt.Printf("received ", i3, " from c3\n")
      } else {
         fmt.Printf("c3 is closed\n")
      }
   default:
      fmt.Printf("no communication\n")
   }
}

根据上方代码所示,定义了c1、c2、c3三个变量,并且使用chan通道。关于写法的解释:一个可以发送 int 类型数据的 channel 一般写为 chan int,根据上方的语法规则:如果有default子句,则执行该语句,故上方代码块执行代码为:no communication

Select用法补充

  • 我们可以使用select来监听channel的数据流动
  • select的用法与switch语法非常类似,由select开始的一个新的选择块,每个选择条件由case语句来描述
  • switch语句可以选择任何使用相等比较的条件相比select由比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作
  • 如果每个 case都未读取到,则Go语言会自动读取default语句所描述的东西,在正常情况下,每个select程序都会有一个输出语句
  • 如果既没有case语句满足,也不存在default语句,则程序进入阻塞状态系统会发出警告,直至疏通

超时判断

var resChan = make(chan int)
// do request
func test() {
    select {
    case data := <-resChan:
        doData(data)
    case <-time.After(time.Second * 3):
        fmt.Println("request time out")
    }
}
​
func doData(data int) {
    //...
}

根据上方代码块可知,我们定义了一个select语句,在第一条case里面,我们将resChan传给data如果在传输的过程中时长超过3s,则会执行第二条case语句

退出

var shouldQuit=make(chan struct{})
fun main(){
    {
        //loop
    }
    //...out of the loop
    select {
        case <-c.shouldQuit:
            cleanUp()
            return
        default:
        }
    //...
}
​
//在另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
close(shouldQuit)

我们定义一个var类型的shouldQuit变量用于结构体的通道,首先我们开启一个select循环,在case里面调用通道方法,并且返回所对应的值;如果不满足,则返回default的值。同时我们在另外一个协程中,如果我们遇到了非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行

判断Channel状态

ch := make (chan int, 5)
//...
data:=0
select {
case ch <- data:
default:
} 

有时候我们不喜欢缓存变慢,这样不利于我们去释放资源,因此我们可以用一个简单的判断方法去进行判断:首先我们开启一个int类型,长度为5的通道,在通道里面我们开启一个select循环,如果data通道的值能被ch所接收,则执行该条语句,否则我们可对default语句进行抛弃data等处理操作

到此这篇关于浅析Go语言中Channel的各种用法的文章就介绍到这了,更多相关Go语言Channel用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Go语言面试题之select和channel的用法

    目录 select 先说switch...case... 再说select...case.. select类比switch 经典示例 运行结果 channel 1.从已经关闭并且没有值的通道中取值 2.从已经关闭并且有值的通道中取值 一图胜千言 总结 select 先说switch...case... switch...case... 很常用,且很好理解.其作用和if...else...一样. 区别是switch...case 相比于if...else...能让我们的代码看起来更清晰,更好理解.

  • 详解Golang中Channel的用法

    如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息. 1 创建channel 每个channel都有一个特殊的类型,也就是channels可发送数据的类型.一个可以发送int类型数据 的channel一般写为chan int.使用内置的make函数,如果第二个参数大于0,则表示创建一个带缓存的channel. ch := make(chan in

  • Go语言的管道Channel用法实例

    本文实例讲述了Go语言的管道Channel用法.分享给大家供大家参考.具体分析如下: channel 是有类型的管道,可以用 channel 操作符 <- 对其发送或者接收值. ch <- v // 将 v 送入 channel ch. v := <-ch // 从 ch 接收,并且赋值给 v. ("箭头"就是数据流的方向.) 和 map 与 slice 一样,channel 使用前必须创建: ch := make(chan int) 默认情况下,在另一端准备好之前,

  • 浅析Go语言中Channel的各种用法

    目录 Go语言基础四 if定义 单层if语法格式 语法警告 多层if语法格式 Switch定义 Type Switch Select定义 Select语句注意事项 Select用法补充 退出 判断Channel状态 Go语言基础四 今天我们要来学习if语句,也就是大家口中的判断语句,我们首先来看一下if语句的定义 if定义 条件语句需要开发者通过指定一个或多个条件,并通过测试条件是否为 true 来决定是否执行指定语句,并在条件为 false 的情况在执行另外的语句.相信读者看到这儿,也是云里雾

  • 浅析R语言中map(映射)与reduce(规约)

    map(映射)与reduce(规约)操作在数据处理中非常常见,R语言的核心是向量化操作,自带的apply系列函数完成了数据框的向量化计算,而purrr包中的map与reduce系列函数很好的拓展了向量化计算,使R语言处理数据更加优雅流畅. purrr包是tidyverse系列中的包,开发者是大名鼎鼎的Hadley Wickham.purrr包中的函数很多,使用最多的是map与reduce系列函数. 安装包 install.packages('purrr') map map表示映射,可以在一个或多

  • golang语言中for循环语句用法实例

    本文实例讲述了golang语言中for循环语句用法.分享给大家供大家参考.具体分析如下: for循环是用来遍历数组或数字的.用for循环遍历字符串时,也有 byte 和 rune 两种方式.第一种为byte,第二种rune. 复制代码 代码如下: package main import ( "fmt" ) func main() { s := "abc汉字" for i := 0; i < len(s); i++ { fmt.Printf("%c,&

  • C语言中memcpy 函数的用法详解

    C语言中memcpy 函数的用法详解 memcpy(内存拷贝函数) c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. void* memcpy(void* destination, const void* source, size_t num); void* dest 目标内存 const void* src 源内存 size_t num 字节个数 库中实现的memcpy函数 struct { ch

  • C语言中qsort函数的用法实例详解

    C语言中qsort函数的用法实例详解 快速排序是一种用的最多的排序算法,在C语言的标准库中也有快速排序的函数,下面说一下详细用法. qsort函数包含在<stdlib.h>中 qsort函数声明如下: void qsort(void * base,size_t nmemb,size_t size ,int(*compar)(const void *,const void *)); 参数说明: base,要排序的数组 nmemb,数组中元素的数目 size,每个数组元素占用的内存空间,可使用si

  • C++语言中std::array的用法小结(神器用法)

    摘要:在这篇文章里,将从各个角度介绍下std::array的用法,希望能带来一些启发. td::array是在C++11标准中增加的STL容器,它的设计目的是提供与原生数组类似的功能与性能.也正因此,使得std::array有很多与其他容器不同的特殊之处,比如:std::array的元素是直接存放在实例内部,而不是在堆上分配空间:std::array的大小必须在编译期确定:std::array的构造函数.析构函数和赋值操作符都是编译器隐式声明的--这让很多用惯了std::vector这类容器的程

  • c语言中scanf的基本用法

    前言 scanf()是C语言的格式输入函数,和printf函数一样被声明在stdio.h头文件中,它的基本使用很简单: 1 int a; 2 scanf("%d",&a);//程序执行到这里时,就等待用户输入:它接收的是变量的地址 //所以一般情况下除了指针型变量和数组名要给变量加上取地址符& 下面主要介绍了C语言中scanf的用法和注意事项,下面来一起看看详细的介绍吧 scanf概念 scanf是格式输入函数,功能是在屏幕上输入指定的信息.简单的来说和printf相似

  • c语言中enum类型的用法案例讲解

    11.10 枚举类型 在实际问题中,有些变量的取值被限定在一个有限的范围内.例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等.如果把这些量说明为整型,字符型或其它类型显然是不妥当的.为此,C语言提供了一种称为"枚举"的类型.在"枚举"类型的定义中列举出所有可能的取值,被说明为该"枚举"类型的变量取值不能超过定义的范围. 应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型. 11.10.

  • C语言中static和auto用法详解

    目录 static的第一种用法:定义为静态变量 static的第二种用法:有理说不清,直接代码见真知 auto的用法:直接代码见真知 总结 static的第一种用法:定义为静态变量 何为静态变量?存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化.就是只进行一次初始化.不理解?看代码! 代码见真知: #include<stdio.h> int main() { void fun(); //定义一个空函数 for(int i=0;i<3;i++) { fun();

  • C语言中switch语句基本用法实例

    目录 switch语句: switch语句的基本格式 C语言switch语句用法 补充:用switch来给成绩等级 总结 switch语句: 实际生活中,需要做出很多选择,大家都知道做选择可以使用if语句,但是如果选择太多,if语句使用起来就会很繁琐,这个时候就需要一个能将代码简化的语句,也就是我们今天的主角switch语句. switch语句是一个多分支选择语句,并且可以支持嵌套. switch语句的基本格式 switch(表达式){case 常量1:语句1case 常量2:语句2defaul

随机推荐