go语言入门学习

短命女 2023-01-13 06:15 244阅读 0赞

文章目录

  • 简介
  • go 数据类型
    • 数据类型基本介绍
    • 类型强制转换
    • 类型断言
    • go 数组和切片数组
    • go 指针
    • go 结构体和接口
    • Map 类型
    • error 错误类型
    • chan 通道
  • go 运算符
    • 算术运算符
    • 关系远算符号
    • 逻辑运算符
    • 位运算符
    • 赋值运算符
  • go 变量和常量
    • go 变量
    • go 常量
  • go 函数
  • go 选择语句
  • go 循环语句
  • go 并发
    • go 关键字
    • channel 通道
  • go 注释
  • go 语言练习

简介

GO 一门开源的编程语言,07 年开发的,09 年开源,12 年出了 go 1 稳定版

go 专门被设计成应用于(搭载了 Web 服务器/存储集群/类似用户的巨型中央服务器)的系统编程语言,在高性能的分布式系统领域来说,go 比其他语言有着更高的开发效率,提供了海量并行支持,对于游戏服务端而言是非常合适的

这里有几个很好的 golang 的学习网址:

  • https://tour.go-zh.org/welcome/1 (中文版)教你编写代码的形式来一步步带你入门 go
  • https://github.com/Unknwon/the-way-to-go_ZH_CN github中电子书《go语言入门指南》
  • https://books.studygolang.com/gopl-zh/ 在线阅读《go语言圣经》
  • https://gobyexample.com 英文版本go的样例

go 数据类型

数据类型基本介绍

  • 布尔型 bool

    1. // 取值 true 或者 false
    2. bool
  • 字符型 byte/rune
    go 不像 java 中特别指定字符类型

    1. // byte 代表 ascll 中一个字符,等价于 uint8
    2. byte
    3. // rune 识别 unicode 编码的字符,中文一个字也是一个字符,等价于 int32
    4. rune
  • 整型 int

    1. // 一般情况 int 优先,8 字节
    2. int
    3. // 无符号
    4. uint8 uint16 uint32 uint64
    5. // 有符号
    6. int8 int16 int32 int64
    7. // 其他
    8. uintptr byte
  • 浮点型 float

    1. // 浮点数
    2. float32 float64
  • 复数类型

    1. // 实数和虚数
    2. complex64 complex128
  • 字符串型

    1. // 字符串
    2. string
  • 错误型

    1. // 错误
    2. error
  • 复合类型

    • 指针类型

      1. *int
      2. **int
    • 数组类型

      1. [3][5]int
    • 切片类型

      1. []int
    • Map 类型

      1. map[string]string
    • 通道类型

      1. // 协程之间传输数据
      2. chan int
    • 结构化类型

      1. type Person struct {
      2. x,y float32
      3. }
    • 接口类型

      1. type IPerson interface {
      2. Born(buf []byte)(n int, err error)
      3. }

类型强制转换

go 语言不像 java 可以做到不同类型数据运算时候做到自动数据转换,go 是没法做到的,它必须手动强制数据类型转换后再去做运算,但是为什么是不支持自动类型转换呢?

  1. // 类型转换
  2. var a int = 2
  3. var b float32 = float32(a)

类型断言

go 数组和切片数组

数组声明和初始化举例

  1. // var 指定数组并初始化
  2. var arr = [3]int{
  3. 1, 2, 3}
  4. // 指定数组并初始化
  5. arr := [3]int{
  6. 1, 2, 3}
  7. // 不确定数组长度,用...来代替
  8. var arr2 = [...]float32{
  9. 1.0, 2.0, 3.0}
  10. arr3 := [...]float32{
  11. 1.0, 2.0, 3.0}
  12. // 声明数组
  13. var arr [10]int
  14. // 二维数组
  15. var arr1 [3][4]int
  16. var arr2 = [1][2]int{
  17. {
  18. 3, 3}
  19. {
  20. 4, 4}
  21. }
  22. // 创建空数组
  23. arr := [][]string{
  24. }

函数中的数组

  1. // 指明数组的大小
  2. func fun1(arr []int) {
  3. }
  4. // 没有指明数组大小
  5. func fun2(arr [2]int) {
  6. }

切片数组(动态数组),可以追加元素,追加时容量可以变大。切片无需说明长度

  1. // 声明切片数组:声明一个未指定大小的数组定义切片,并且 a 切片数组在没有初始化之前 a 是 nil,a 的长度和容量都是 0
  2. var a []int
  3. // 创建切片:make 函数创建切片,下面 make 函数第二个参数代表长度
  4. var a = make([]int, 5)
  5. b := make([]int, 5)
  6. // 创建切片:下面 make 第二个参数是数组长度,第三个参数是数组的容量
  7. c := make([]int, 5, 6)
  8. // 数组的地址值赋值,有多种形式 s := arr[startIndex:endIndex],s := arr[startIndex:],s := arr[:endIndex]
  9. var arr []int = [3]int {
  10. 1, 2, 3}
  11. s := arr[:]
  12. // 创建空切片,并进行 append 追加元素
  13. var arr1 []int
  14. arr1 = append(arr1, 2, 3, 6)
  15. // 将 arr1 copy 到 arr2(内容的拷贝)
  16. arr2 := make([]int, len(arr1), cap(arr1)*2)
  17. copy(arr2, arr1)
  18. fmt.Println(arr2)

make,len,cap 函数的使用

  1. var arr = make([]int, 5, 6)
  2. fmt.Printf("%d, %d, %v", len(arr), cap(arr), arr);

go 指针

  1. // 变量的地址值
  2. var a int = 10
  3. fmt.Println(&a)
  4. // 指针使用
  5. var a int = 10
  6. var b *int
  7. b = &a
  8. fmt.Println(a)
  9. fmt.Println(*b)
  10. // 空指针 a 就是 nil,而 *a 的值是 0
  11. var a *int
  12. // 数组指针
  13. var arr [3]*int
  14. // 指向指针的指针
  15. var a **int
  16. // 函数中指针类型传参
  17. func fun(x *int, y *int) {
  18. }

go 结构体和接口

结构体

  1. // 结构体
  2. type Person struct {
  3. name string
  4. age int
  5. address string
  6. }
  7. func main() {
  8. // 初始化接口体的几种方式
  9. fmt.Println(Person("liming", 12, "北京市"))
  10. fmt.Println(Person(name:"liming", age:12, address:"北京市"))
  11. fmt.Println(Person(name:"liming", age:12))
  12. // 另一种初始化方式
  13. var person Person
  14. person.name = "liming"
  15. person.age = 12
  16. person.address = "北京市"
  17. fmt.Println(person.name)
  18. }
  19. func fun1(person1 Person) {
  20. }
  21. func fun2(person2 *Person) {
  22. }

接口

  1. // Person 接口
  2. type Person interface {
  3. call()
  4. }
  5. // 结构体
  6. type Student struct {
  7. }
  8. // 实现接口的方法
  9. func(student Student) call() {
  10. fmt.Println("我是学生")
  11. }

Map 类型

无序的键值对集合,Map 是无序的,无法决定它的返回顺序,使用哈希表来实现

  1. // 声明 map,并给 map 赋值,然后遍历 map,查看元素在集合中是否存在,map1 一开始是 nil
  2. var map1 map[string]string
  3. map2 := make(map[string]string)
  4. map3 := map[string]string{
  5. "c":"ccc", "d":"ddd"}
  6. map1["a"] = "aaa"
  7. map1["b"] = "bbb"
  8. for ch := range map1 {
  9. fmt.Println(map1[ch])
  10. }
  11. value, ok := map1["a"]
  12. if (ok) {
  13. } else {
  14. }
  15. // delete 函数
  16. delete(map3, "c")

error 错误类型

go 语言通过内置的错误接口提供了非常简单的错误处理机制,error 类型是一个接口类型

  1. type error interface {
  2. Error() string
  3. }

我们可以在最后的返回值中返回 error 信息

  1. func function() (int, error) {
  2. return 5, errors.New("错误信息")
  3. }
  4. func main() {
  5. result, err := function()
  6. }

chan 通道

具体讲解可以看下方的 channel 通道

go 运算符

运算优先级类似 java

算术运算符

加减乘除,求余,自增,自减和 java 一样

关系远算符号

== != > < >= <=这些和 java 都是一样的

逻辑运算符

&& || !这些和 java 都是一样的

位运算符

& | ^ << >>

赋值运算符

= += -= *= /= %= <<= >>= &= ^= |=和 java 一样

go 变量和常量

go 变量

声明变量用 var,示例如下

  1. // 声明一个变量
  2. var param string
  3. // 声明多个变量(非全局变量)
  4. var param1, param2 int
  5. param1, param2 = 1, 2
  6. var param1, param2 = 1, 2
  7. // 声明多个变量(全局变量)
  8. var(
  9. param1 string
  10. param2 int
  11. )
  12. // 自行判断变量
  13. var param = true
  14. // var 和 := 等同
  15. var param int
  16. param1 := 1

方法中指定变量没有初始值则有默认值

  • 数值对应 0
  • string 对应 “”
  • bool 对应 false
  • 数组,指针,map,通道,error,方法等类型则是对应 nil

值类型和引用类型

  • 值类型:变量直接指向内存中的值(int,float,bool,string),也就是说等号将值给一个变量时候是将内存中的值进行了拷贝,&param 就行获取内存地址,值类型变量存储在栈内存中,
  • 引用类型:变量存储值的地址值

go 常量

常量示例

  1. // 局部
  2. const LENGTH = 1
  3. const WIDTH, CIRCLE = 1, 2
  4. // 全局
  5. const(
  6. a = "aaa"
  7. b = 1
  8. )
  9. // 特殊常量 iota,const 语句块中表示行索引,每当遇到新的 iota 时候重新计数行索引
  10. // 下面 a 结果是 0,b 结果是 1,c 结果是 2
  11. const(
  12. a = iota
  13. b
  14. c
  15. )

go 函数

go 语言最少有一个 main

  1. // 返回一个值
  2. func max(num1, num2 int) int {
  3. }
  4. // 返回多个值
  5. func swap(nums1, nums2 int) (int, int) {
  6. return nums2, nums1
  7. }
  8. func main() {
  9. a, b := swap(1, 2)
  10. }

函数闭包,go 支持匿名函数,可作为闭包,匿名函数优越在于可以使用函数内的变量,不必申明

  1. func getSequence() func() int {
  2. return func() int {
  3. return 1
  4. }
  5. }

go 选择语句

if else 和 java 一样,但是小括号是不用加的,并且 else 不可单独另作一行

switch 语句如下:

  1. var a int = 1
  2. switch a {
  3. case 1: xxx
  4. case 2: xxx
  5. default: xxx
  6. }
  7. switch {
  8. case true: xxx
  9. default: xxx
  10. }

select 语句类似一个通信的 switch 语句,每个 case 都必须是一个通信操作,要么接收要么发送;select 随机执行一个可运行的 case,如果没有 case 运行,它将被阻塞

格式如下:

  1. select {
  2. case xxx : yyy
  3. default : yyy
  4. }

go 循环语句

for 循环如下

  1. // for 循环一种形式
  2. for i := 0; i < 10; i++ {
  3. }
  4. // for 类似 while
  5. for i < 10 {
  6. }
  7. // for 无限循环
  8. for {
  9. }
  10. // foreach range 用来遍历字符串数组等进行遍历,还可以用在键值对上,
  11. strings := []string{
  12. "aaa", "bbb"}
  13. for i,s := range strings {
  14. fmt.println(i, s);
  15. }
  16. kvs := map[string]int{
  17. "a":1, "b":2}
  18. for k,v := range kvs {
  19. fmt.Printf("%s, %d", k, v)
  20. }

另外 break,continue,goto 和 java 一样

go 并发

go 关键字

go 语言支持并发,通过 go 关键字来开启 goroutine 即可,goroutine 是轻量级线程,其是由 golang 运行时进行管理的,下面举例说明

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func say(s string) {
  7. for i := 0; i < 5; i++ {
  8. time.Sleep(100 * time.Millisecond)
  9. fmt.Println(s)
  10. }
  11. }
  12. func main() {
  13. // 通过 g 关键字开启一个 goroutine 轻量级线程
  14. go say("aaa")
  15. say("bbb")
  16. }

channel 通道

通道关键字是 chan,可以在两个 goroutine 之间传递一个指定类型的值,<-可以用来指定通道方向,如果没有指定方向,则为双向通道,下方举例使用通道

  1. package main
  2. import "fmt"
  3. func main() {
  4. var a int = 5
  5. // 创建一个通道
  6. b := make(chan int)
  7. // 把 a 给通道 b
  8. go function(a, b)
  9. a2 := <- b
  10. fmt.Println(a2)
  11. }
  12. func function(a int, b chan int) {
  13. b <- a
  14. }

chan 通道可以设置缓冲区大小,发送端发送的数据可以放在缓冲区中

如果通道不带缓冲区,发送方会阻塞,直到接收方从通道中接收了值

如果通道带有缓冲区,发送方会阻塞,直到发送的数据被拷贝到了缓冲区,如果缓冲区已经满了,则又会被阻塞,直到接收方开始消费缓冲区

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 设置缓冲区大小为 2
  5. ch := make(chan int, 2)
  6. ch <- 3
  7. ch <- 5
  8. // 获取通道中的两个数据,这里打印出 3
  9. fmt.Println(<-ch)
  10. // 这里打印出来 4
  11. fmt.Println(<-ch)
  12. }

通道关闭为 close(通道),通道的遍历依然是通过 range

  1. func main() {
  2. // 声明一个缓冲区大小为 3 的通道
  3. ch := make(chan int, 3)
  4. ch <- 3
  5. ch <- 1
  6. ch <- 9
  7. close(ch)
  8. for i := range ch {
  9. fmt.Println(i)
  10. }
  11. }

go 注释

  1. // 单行注视
  2. /*
  3. 多行注释
  4. */

go 语言练习

递归实现求斐波那契数列

  1. package main
  2. import "fmt"
  3. func main() {
  4. // n = 1 时候值为 1,n = 2 时值为 1,求 n = 10 时候值为多少?使用递归
  5. fmt.Println(function(10))
  6. }
  7. /*
  8. 斐波那契函数
  9. */
  10. func function(n int) int {
  11. if n <= 0 {
  12. return 0
  13. } else if n == 1 {
  14. return 1
  15. } else if n == 2 {
  16. return 1
  17. } else {
  18. return function(n-1) + function(n-2)
  19. }
  20. }

发表评论

表情:
评论列表 (有 0 条评论,244人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Go语言入门

    Go语言入门 简介 Go是一门由Google开发的开源编程语言,旨在提供高效、可靠和简洁的软件开发工具。Go具有静态类型、垃圾回收、并发性和高效编译的特点,适用于构

    相关 GO语言入门

    GO语言概述 什么是GO语言 Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言 GO语言特性

    相关 go语言入门

    一、Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、数组安全、编译迅速 二、语言用途 Go 语言被设计成一门应用于搭载 Web 服务器,存