Go内置关键字分析(二) - Go语言中文社区

Go内置关键字分析(二)


Go语言25个内置关键字分析(一):https://blog.csdn.net/sinat_24568041/article/details/80904271

Go关键字按类型不同做如下区分(注:图片来自网络,若有侵权,请联系删除):


2.2引用类型

(1) Map

作用:用于声明map类型数据

    a.Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

    b.Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

    c.go语言中,map使用hash表实现,由于go是强类型语言,所以必须为map的键和值指定具体的类型,这些键或者值的类型可以是字符串、整型、指向结构体的指针等。如下:

Map的键和值都是字符串类型:

go m := make(map[string]string)

定义:可以使用内建函数 make 也可以使用 map 关键字来定义 Map:

/* 声明变量,默认 map 是 nil */

var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */

map_variable := make(map[key_data_type]value_data_type)

注:如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

 演示:

/*创建和使用map*/

package main

 

import "fmt"

 

func main() {

   var countryCapitalMap map[string]string

   /* 创建集合 */

   countryCapitalMap = make(map[string]string)

   

   /* map 插入 key-value 对,各个国家对应的首都 */

   countryCapitalMap["France"] = "Paris"

   countryCapitalMap["Italy"] = "Rome"

   countryCapitalMap["Japan"] = "Tokyo"

   countryCapitalMap["India"] = "New Delhi"

   

   /* 使用 key 输出 map 值 */

   for country := range countryCapitalMap {

      fmt.Println("Capital of",country,"is",countryCapitalMap[country])

   }

   

   /* 查看元素在集合中是否存在 */

   captial, ok := countryCapitalMap["United States"]

   /* 如果 ok 是 true, 则存在,否则不存在 */

   if(ok){

      fmt.Println("Capital of United States is", captial)  

   }else {

      fmt.Println("Capital of United States is not present")

   }

}

(2) Range

作用:Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对的 key 值。如下表所示:

Range expression

1st value

2nd valueoptional

Notes

array[n]E,*[n]E

index int

value E[i]

 

slice []E

index int

value E[i]

 

string abcd

index int

rune int

对于string,range迭代的是Unicode而不是字节,所以返回的值是rune

map map[k]v

keyk

value v

 

channel

element

none

 


演示:
(演示代码摘自:
http://www.runoob.com/go/go-range.html)

package main

import "fmt"

func main() {

    //这是我们使用range去求一个slice的和。使用数组跟这个很类似

    nums := []int{2, 3, 4}

    sum := 0

    for _, num := range nums {

        sum += num

    }

    fmt.Println("sum:", sum)

    //在数组上使用range将传入index和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。

    for i, num := range nums {

        if num == 3 {

            fmt.Println("index:", i)

        }

    }

    //range也可以用在map的键值对上。

    kvs := map[string]string{"a": "apple", "b": "banana"}

    for k, v := range kvs {

        fmt.Printf("%s -> %sn", k, v)

    }

    //range也可以用来枚举Unicode字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。

    for i, c := range "go" {

        fmt.Println(i, c)

    }

}

2.3自定义类型

(1)Interface

作用:定义接口

定义:

/* 定义接口 */

type interface_name interface {

   method_name1 [return_type]

   method_name2 [return_type]

   method_name3 [return_type]

   ...

   method_namen [return_type]

}

说明:

    a. 不需要显式声明实现某个接口,只要实现相关方法就实现了接口

    b. 接口也可以组合(相当于继承)

    c. 可以试探是否为某个struct或interface的实例(ok pattern)

    d. 可以使用匿名接口

    e. 空接口可以看作是所有struct都实现了的。匿名空接口直接写成:interface{}

(2)Struct

作用:结构体,也是符合数据类型

定义: 

type typeName struct {

...

}

    注:Go中的struct不仅可以将struct作为匿名字段,用type自定的类型以及内置的类型都可以作为匿名字段

(3)Type

作用:定义接口、定义结构体、类型定义、类型别名、类型查询

具体可参考:https://blog.csdn.net/hzwy23/article/details/79890778

3. 流程控制类

3.1并发类

(1)Go

作用:go 关键字用来创建 goroutine (协程),实现并发

演示:

//go 关键字放在方法调用前新建一个 goroutine 并让他执行方法体

go GetThingDone(param1, param2);

 

//上例的变种,新建一个匿名方法并执行

go func(param1, param2) {

}(val1, val2)

 

//直接新建一个 goroutine 并在 goroutine 中执行代码块

go {

    //do someting...

}

(2)Select

作用:用于选择不同类型的通讯

参考:https://blog.csdn.net/wo198711203217/article/details/65442288

(3)Channel

作用:用于channel通讯

演示:使用 go 关键字和 channel 实现非阻塞调用

/**

 * 每次调用方法会新建一个 channel : resultChan,

 * 同时新建一个 goroutine 来发起 http 请求并获取结果。

 * 获取到结果之后 goroutine 会将结果写入到 resultChan。

 */

func UnblockGet(requestUrl string) chan string {

    resultChan := make(chan string)

    go func() {

        request := httplib.Get(requestUrl)

        content, err := request.String()

        if err != nil {

            content = "" + err.Error()

        }

        resultChan <- content

    } ()

    return resultChan

3.2 单任务流程控制

3.2.1 单分支流程

If/else

作用:用于条件判断

演示:

if age >= 0 {

        fmt.Println("a")

    } else {

        fmt.Println("b")

    }

3.2.2多分支流程控制

Switch & Case & Default & fallthrough

作用:用于条件判断

说明:

    Goswitch非常灵活。表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项,而如果switch没有表达式,它会匹配true。这产生一种可能——使用switch编写if-else-if-else判断序列。它不会匹配失败后自动向下尝试,但是可以使用 fallthrough 使其这样做。用default可以指定当其他所有分支都不匹配的时候的行为。

演示:

package main



import "fmt"

import "time"

 

func main() {

 

         i := 2

 

         fmt.Print("write", i, " as ")

 

         switchi {

 

         case 1:

                   fmt.Println("one")

         case 2:

                   fmt.Println("two")

         case 3:

                   fmt.Println("three")

         }

         switchtime.Now().Weekday() {

         casetime.Saturday, time.Sunday:

                   fmt.Println("it'sthe weekend")

         default:

                   fmt.Println("it'sa weekday")

         }

 

         t :=time.Now()

 

         switch{

         caset.Hour() < 12:

                   fmt.Println("it'sbefore noon")

         default:

                   fmt.Println("it'safter noon")

         }

} 

3.2.3循环流程

For

作用:用于循环控制

定义:

for init; condition; post { }

for condition { }

for { }

    注:init: 一般为赋值表达式,给控制变量赋初值;

                    condition: 关系表达式或逻辑表达式,循环控制条件;

                    post: 一般为赋值表达式,给控制变量增量或减量。

     参考:http://www.runoob.com/go/go-for-loop.html

执行过程:

    a.先对表达式1赋初值;

    b.判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

执行流程:


演示:

package main

 

import "fmt"

 

func main() {

 

   var b int = 15

   var a int

 

   numbers := [6]int{1, 2, 3, 5}

 

   /* for 循环 */

   for a := 0; a < 10; a++ {

      fmt.Printf("a 的值为: %dn", a)

   }

 

   for a < b {

      a++

      fmt.Printf("a 的值为: %dn", a)

   }

 

   for i,x:= range numbers {

      fmt.Printf("第 %d 位 x 的值 = %dn", i,x)

   }   

}

3.2.4 goto& Break & continue

作用:跳转语句关键字

说明:

    关键字break,goto,continue,作用其实跟java语言的没啥区别,但是在java中goto是保留字段,没有任何意义,但是java中的break和continue的作用跟golang一样,可以跳出或者跳转执行指定的标签,c++中有标签,但是他的break,和continue不能说指定跳出和继续指定的标签,但是他的goto可以实现这个功能,条件成立,跳转到指定标签的执行语句中

演示:

break关键字

LABLE1:

for {

   for i := 1; i < 10; i++ {

      if i == 4 {

         break LABLE1 //跳出定义了标签层

      }

   }

}

fm.Println("break is over")

 

goto关键字

for {

   for i := 1; i < 10; i++ {

      if i == 4 {

         goto LABLE2 //调整了执行位置,如果是标签是放在for语句

         //之前,又是重新开始执行

      }

   }

}

 

LABLE2:

fm.Println("goto is over")

 

continue关键字

LABLE3:

for i := 1; i < 10; i++ {

   for {

      fm.Print(i)

      continue LABLE3 //继续执行定义了标签层

   }

}

 

自增符号++和自减符号--

他这个跟java语言的还是有区别的,它是作为一个语句,而不是作为一个表达式,他不能放在变量的左边,只能放在右边,譬如

a:=1

//a=a++ 或者++a,这样是错误的

只能a++,因为他是一个语句,同样道理,自减符号也是一样。

 

fm.Println("continue is over")

3.2 延时型流程控制

Defer

作用:在函数退出之前执行

说明:

    a.Go语言中,defer语句会在该函数结束的时候被调用,即使后面的语句运行时出现异常了defer语句仍然会被执行。

    b.需要注意的是,如果defer语句中引用了参数,则该参数的值将是程序到defer这一行的时候的值,而与后面的语句没有关系。

    注:https://studygolang.com/articles/3758

演示:

package main

 

import "fmt"

 

func main() {

   func_b_0()

   func_b_1()

   func_b_2()

}

 

func func_b_0() {

   fmt.Println("func_b_0...top")

   a := 5

   defer fmt.Println("a=", a)

   a++

}

func func_b_1() {

   fmt.Println("func_b_1...top")

   a := 5

   defer func() {

      fmt.Println("a=", a)

   }()

   a++

}

func func_b_2() {

   fmt.Println("func_b_2...top")

   a := 5

   defer func(a int) {

      fmt.Println("a=", a)

   }(a)

   a++

}
注:由于作者是初入Go语言时间不长,文章中有些技术点表述可能不是很详细或者有问题,还望各位海涵,后期会逐渐增加,若有问题可联系作者,谢谢。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/sinat_24568041/article/details/80933687
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-12 20:50:16
  • 阅读 ( 702 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢