Go语言 记者招待会

原创
08/20 15:15
阅读数 60

我是悟空 

爱学习的程序猿,自主开发了Java学习平台、PMP刷题小程序。目前主修Java、多线程、SpringBoot、SpringCloud、k8s。本公众号不限于分享技术,也会分享工具的使用、人生感悟、读书总结。

本篇来讲下Go的基本使用,欢迎点赞/转发/在看!

主持人:欢迎Go同学

欢迎Go同学

Go同学:

大家好,我叫Go,一个开源的编程语言,能够让软件变得构造简单且高效。

1.记者:Go你好,请问你和其他语言同学有什么区别?

Go同学:

  • 简洁、快速、安全

  • 并行、有趣、开源

  • 内存管理、数组安全、编译迅速

2.记者:Go你好,请问您可以用在哪些地方?

Go同学:

  • 搭载 Web 服务器,存储集群或类似用途的巨型中央服务器。
  • 提供了海量并行的支持,适合游戏服务端的开发

3.记者:Go同学,听说您有强大的并发功能,可以给我们讲下吗?

Go同学:

只需要通过 go 关键字来开启 goroutine 即可。

goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的

goroutine 语法格式:

go 函数名( 参数列表 )

例如:

go f(x, y, z)

Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。同一个程序中的所有 goroutine 共享同一个地址空间。

package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say("test")
    say("hello")
}

执行以上代码,输出的 hello 和 world 是没有固定先后顺序。因为它们是两个 goroutine 在执行:

test
test
hello
hello
test
hello
hello
test
test
hello

4.记者:请问多线程之间如何传递数据?

Go同学:

通道(channel)是用来传递数据的一个数据结构

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v

声明一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:

ch := make(chan int)

注意:默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据。

以下实例通过两个 goroutine 来计算数字的平方-5,在 goroutine 完成计算后,它会计算两个结果的和:

package main

import "fmt"

func square(s int, c chan int) {
    result := s * s - 5
    c <- result // 把 result 发送到通道 c
}

func main() {
        c := make(chan int)
        go square(3, c)
        go square(4, c)
        x, y := <-c, <-c // 从通道 c 中接收

        fmt.Println(x, y, x+y)
}

输出结果为:

4 11 15

通道缓冲区

  • 通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小:
ch := make(chan int, 100)
  • 带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。

  • 由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了。

注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞。

package main

import "fmt"

func main() {
    // 这里我们定义了一个可以存储整数类型的带缓冲通道
        // 缓冲区大小为3
        ch := make(chan int3)

        // 因为 ch 是带缓冲的通道,我们可以同时发送3个数据
        // 而不用立刻需要去同步读取数据
        ch <- 100
        ch <- 200
        ch <- 300
    
        // 获取这两个数据
        fmt.Println(<-ch)
        fmt.Println(<-ch)
     fmt.Println(<-ch)
}

输出结果

100
200
300

Go 遍历通道与关闭通道

Go 通过 range 关键字来实现遍历读取到的数据

package main

import (
        "fmt"
)

func square(n int, c chan int) {
 
        for i := 1; i <= n; i++ {
   x := i * i
            c <- x
        }
        close(c)
}

func main() {
        c := make(chan int5)
        go square(5, c)
        // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 5 个
        // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 5 个数据
        // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数会报死锁的错误提示。
        for i := range c {
                fmt.Println(i)
        }
}

输出结果:

1
4
9
16
25

通道不关闭,造成死锁的错误提示:

1
4
9
16
25

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
 /box/main.go:23 +0xf1

Exited with error status 2

5.记者:Go同学,请问怎么安装Go呢?

Go同学:

  • 我支持的系统:Linux、FreeBSD、Mac OS、Windows。

  • 安装包下载地址为:https://golang.org/dl/。

  • 安装步骤去上面说的网站看下就知道啦

安装包下载

6.记者:Go同学,请问基础语法是怎么样的?

Go同学:

  • 由多个标记组成,可以是关键字,标识符,常量,字符串,符号。
  • 在 Go 程序中,一行代表一个语句结束,不需要分号。
  • 注释不会被编译,每一个包应该有相关注释。
  • 标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
  • Go 语言的字符串可以通过 + 实现
  • Go 代码中会使用到25 个关键字或保留字
  • Go 语言中变量的声明必须使用空格隔开

7.记者:Go你好,数据类型的是怎么样的?

Go同学:

  • 布尔型
    • 常量 true 或者 false
  • 数字类型
    • uint8、uint16、uint32**、 uint64int8、int16、int32、int64、float32、float64、 complex64、**complex128
  • 字符串类型:
  • 派生类型:
    • (a) 指针类型(Pointer)
    • (b) 数组类型
    • (c) 结构化类型(struct)
    • (d) Channel 类型
    • (e) 函数类型
    • (f) 切片类型
    • (g) 接口类型(interface)
    • (h) Map 类型

8.记者:Go同学,请问您如何定义变量?

Go同学:

  • 声明变量的一般形式是使用 var 关键字
  • 第一种,指定变量类型,如果没有初始化,则变量默认为零值
  • 第二种,根据值自行判定变量类型。
  • 第三种,省略 var, 注意 *:=* 左侧如果没有声明新的变量,就产生编译错误

9.记者:Go同学,您如何定义常量?

Go同学:

  • const identifier [type] = value,略类型说明符 [type],因为编译器可以根据变量的值来推断其类型
  • 常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型

10.记者:Go同学,请问你有哪些运算符

Go同学:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 其他运算符

11.记者:Go同学,您有哪些条件语句?

Go同学:if,if else,swith,select

12.记者:Go你好,循环有哪些需要注意的?

Go同学:我有for 循环,可以用break/continue/goto语句

13.记者:Go同学,请问如何定义函数

Go同学:

func function_name( [parameter list] ) [return_types] {
   函数体
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,函数名和参数列表一起构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

14.记者:Go语言有哪些变量作用域

Go同学:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

15.记者:Go你好,数组该怎么使用?

Go同学:

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

var variable_name [SIZE] variable_type

Go语言初始化数组:

var test = [5float32{200.02.03.1420.0100.0}

可以通过索引获取/设置数组中的值:

test[4]
test[2] = 100

16.记者:Go同学,请问如何处理异常?

Go同学:

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

error类型是一个接口类型,这是它的定义:

type error interface {
    Error() string
}

我们可以在编码中通过实现 error 接口类型来生成错误信息。

函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:

func Sqrt(f float64) (float64, error) {
    if f < 0 {
        return 0, errors.New("math: square root of negative number")
    }
    // 实现
}

17.记者:Go同学,有什么好用的开发工具吗?

Go同学:

  • IDEA

IntelliJ idea是非常强大的一款IDE,支持丰富的插件。需要安装两个插件Go和File Watcher

  • GoLand

GoLand 是 Jetbrains 家族的 Go 语言 IDE,有 30 天的免费试用期。

  • LiteIDE

LiteIDE 是一款开源、跨平台的轻量级 Go 语言集成开发环境(IDE)

  • Eclipse

参考资料:

https://www.runoob.com/go/go-tutorial.html

关于我

悟空
爱学习的程序猿,自主开发了Java学习平台、PMP刷题小程序。目前主修Java、多线程、SpringBoot、SpringCloud、k8s。本公众号不限于分享技术,也会分享工具的使用、人生感悟、读书总结。

更多内容



长按二维码关注

领取架构师资料


帅的人都点了在看! 

本文分享自微信公众号 - 悟空聊架构(PassJava666)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部