Go语言学习之路

Posted 果子哥丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言学习之路相关的知识,希望对你有一定的参考价值。

Go语言学习之路

Go语言简介

Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。

对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。

第一个Go程序:
go安装地址:https://golang.google.cn/dl/
接下来我们来编写第一个 Go 程序 hello.go(Go 语言源文件的扩展是 .go),代码如下:

hello.go文件

package main

import "fmt"

func main() 
    fmt.Println("Hello, World!")

要执行 Go 语言代码可以使用 go run 命令。

$ go run hello.go 
Hello, World!

此外我们还可以使用 go build 命令来生成二进制文件:
$ go build hello.go 
$ ls
hello    hello.go
$ ./hello 
Hello, World!

Go语言结构

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释
package main  // 包声明

import "fmt"  // 引用包

func main()   // 函数必须包含。 需要注意的是  不能单独放在一行
   /* 这是我的第一个简单的程序 */
   fmt.Println("Hello, World!")  

  • 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);
  • 当标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
文件结构:

Test
--helloworld.go

myMath
--myMath1.go
--myMath2.go
// helloworld.go
package main

import (
"fmt"
"./myMath"
)

func main()
    fmt.Println("Hello World!")
    fmt.Println(mathClass.Add(1,1))
    fmt.Println(mathClass.Sub(1,1))

// myMath1.go
package mathClass
func Add(x,y int) int 
    return x + y

// myMath2.go
package mathClass
func Sub(x,y int) int 
    return x - y

格式化字符串:
fmt.Sprintf 格式化字符串并赋值给新串:

package main

import (
    "fmt"
)

func main() 
   // %d 表示整型数字,%s 表示字符串
    var stockcode=123
    var enddate="2020-12-31"
    var url="Code=%d&endDate=%s"
    var target_url=fmt.Sprintf(url,stockcode,enddate)
    fmt.Println(target_url)

Go语言变量
声明变量的一般形式是使用 var 关键字:

var identifier type

可以一次声明多个变量:
var identifier1, identifier2 type

intVal := 1 相等于:
var intVal int 
intVal =1 
package main
import "fmt"
func main() 
    var a string = "Runoob"  // a1 := "Ruoob"
    fmt.Println(a)

    var b, c int = 1, 2
    fmt.Println(b, c)


//这种不带声明格式的只能在函数体中出现
//g, h := 123, "hello"
  • 如果你在定义变量 a 之前使用它,则会得到编译错误 undefined: a。
  • 如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误,a declared but not used。
  • 在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。但是全局变量是允许声明后不使用的。

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

  • 显式类型定义: const b string = “abc”
  • 隐式类型定义: const b = “abc”

Go语言运算符

   /*  & 和 * 运算符实例 */
   ptr = &a     /* 'ptr' 包含了 'a' 变量的地址 */
   fmt.Printf("a 的值为  %d\\n", a);
   fmt.Printf("*ptr 为 %d\\n", *ptr);

Go语言循环语句
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
和 C 语言的 for 一样:

for init; condition; post  

init: 一般为赋值表达式,给控制变量赋初值;
condition: 关系表达式或逻辑表达式,循环控制条件;
post: 一般为赋值表达式,给控制变量增量或减量。

和 C 的 while 一样:

for condition  

和 C 的 for(;;) 一样:

for  

for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap 
    newMap[key] = value

计算 1 到 10 的数字之和:

package main

import "fmt"

func main() 
        sum := 0
        for i := 0; i <= 10; i++ 
                sum += i
        
        fmt.Println(sum)

init 和 post 参数是可选的,我们可以直接省略它,类似 While 语句。

package main

import "fmt"

func main() 
        sum := 1
        for ; sum <= 10; 
                sum += sum
        
        fmt.Println(sum)

        // 这样写也可以,更像 While 语句形式
        for sum <= 10
                sum += sum
        
        fmt.Println(sum)

无限循环:要停止无限循环,可以在命令窗口按下ctrl-c 。

package main

import "fmt"

func main() 
        sum := 0
        for 
            sum++ // 无限循环下去
        
        fmt.Println(sum) // 无法输出

For-each range 循环
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

for key, value := range oldMap 
    newMap[key] = value

package main
import "fmt"

func main() 
        strings := []string"google", "runoob"
        for i, s := range strings 
                fmt.Println(i, s)
        


        numbers := [6]int1, 2, 3, 5
        for i,x:= range numbers 
                fmt.Printf("第 %d 位 x 的值 = %d\\n", i,x)
          

以上实例运行输出结果为:

0 google
1 runoob
第 0 位 x 的值 = 11 位 x 的值 = 22 位 x 的值 = 33 位 x 的值 = 54 位 x 的值 = 05 位 x 的值 = 0

Go语言函数

Go 语言函数定义格式如下:

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

package main

import "fmt"

func main() 
   /* 定义局部变量 */
   var a int = 100
   var b int = 200
   var ret int

   /* 调用函数并返回最大值 */
   ret = max(a, b)

   fmt.Printf( "最大值是 : %d\\n", ret )


/* 函数返回两个数的最大值 */
func max(num1, num2 int) int 
   /* 定义局部变量 */
   var result int

   if (num1 > num2) 
      result = num1
    else 
      result = num2
   
   return result

函数返回多个值

package main

import "fmt"

func swap(x, y string) (string, string) 
   return y, x


func main() 
   a, b := swap("Google", "Runoob")
   fmt.Println(a, b)

以上实例执行结果为:
Runoob Google

语言函数引用传递值
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

引用传递指针参数传递到函数内,以下是交换函数 swap() 使用了引用传递:
允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。

package main

import "fmt"

func main() 
   /* 定义局部变量 */
   var a int = 100
   var b int= 200

   fmt.Printf("交换前,a 的值 : %d\\n", a )
   fmt.Printf("交换前,b 的值 : %d\\n", b )

   /* 调用 swap() 函数
   * &a 指向 a 指针,a 变量的地址
   * &b 指向 b 指针,b 变量的地址
   */
   swap(&a, &b)

   fmt.Printf("交换后,a 的值 : %d\\n", a )
   fmt.Printf("交换后,b 的值 : %d\\n", b )


func swap(x *int, y *int) 
   var temp int
   temp = *x    /* 保存 x 地址上的值 */
   *x = *y      /* 将 y 值赋给 x */
   *y = temp    /* 将 temp 值赋给 y */

以上代码执行结果为:

交换前,a 的值 : 100
交换前,b 的值 : 200
交换后,a 的值 : 200
交换后,b 的值 : 100

Go语言数组

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

var variable_name [SIZE] variable_type
var balance [10] float32
var balance = [5]float321000.0, 2.0, 3.4, 7.0, 50.0

如果数组长度不确定,可以使用 … 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

var balance = [...]float321000.0, 2.0, 3.4, 7.0, 50.0
或
balance := [...]float321000.0, 2.0, 3.4, 7.0, 50.0

如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

//  将索引为 1 和 3 的元素初始化
balance := [5]float321:2.0,3:7.0

1:2  3:7

访问数组元素

var salary float32 = balance[9]
package main

import "fmt"

func main() 
   var n [10]int /* n 是一个长度为 10 的数组 */
   var i,j int

   /* 为数组 n 初始化元素 */        
   for i = 0; i < 10; i++ 
      n[i] = i + 100 /* 设置元素为 i + 100 */
   

   /* 输出每个数组元素的值 */
   for j = 0; j < 10; j++ 
      fmt.Printf("Element[%d] = %d\\n", j, n[j] )
   

Go语言指针

什么是指针?
一个指针变量指向了一个值的内存地址。
类似于变量和常量,在使用指针前你需要声明指针。指针声明格式如下:

var var_name *var-type

var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:
var ip *int        /* 指向整型*/
var fp *float32    /* 指向浮点型 */

如何使用指针?
指针使用流程:

  • 定义指针变量。
  • 为指针变量赋值。
  • 访问指针变量中指向地址的值。

在指针类型前面加上 * 号(前缀)来获取指针所指向的内容。

package main

import "fmt"

func main() 
   var a int= 20   /* 声明实际变量 */
   var ip *int        /* 声明指针变量 */

   ip = &a  /* 指针变量的存储地址 */

   fmt.Printf("a 变量的地址是: %x\\n", &a  )

   /* 指针变量的存储地址 */
   fmt.Printf("ip 变量储存的指针地址: %x\\n", ip )

   /* 使用指针访问值 */
   fmt.Printf("*ip 变量的值: %d\\n", *ip )

空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。

package main
import "fmt"
func main() 
   var  ptr *int
   fmt.Printf("ptr 的值为 : %x\\n", ptr  )


输出结果:ptr 的值为 : 0

空指针判断:

if(ptr != nil)     /* ptr 不是空指针 */
if(ptr == nil)    /* ptr 是空指针 */

整型指针数组

指向指针的指针
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。

当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:

指向指针的指针变量声明格式如下:

var ptr **int;  // 访问指向指针的指针变量值需要使用两个 * 号
package main

import "fmt"

func main() 

   var a int
   var ptr *int
   var pptr **int

   a = 3000

   /* 指针 ptr 地址 */
   ptr = &a

   /* 指向指针 ptr 地址 */
   pptr = &ptr

   /* 获取 pptr 的值 */
   fmt.Printf("变量 a = %d\\n", a )
   fmt.Printf("指针变量 *ptr = %d\\n", *ptr )
   fmt.Printf("指向指针的指针变量 **pptr = %d\\n", **pptr)


以上实例执行输出结果为:
变量 a = 3000
指针变量 *ptr = 3000
指向指针的指针变量 **pptr = 3000

Go语言结构体

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

定义结构体:
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

type struct_variable_type struct 
   member definition
   member definition
   ...
   member definition


一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_variable_type value1, value2...valuen
或
variable_name := structure_variable_type  key1: value1, key2: value2..., keyn: valuen
package main

import "fmt"

type Books struct 
   title string
   author string
   subject string
   book_id int



func main() 

    // 创建一个新的结构体
    fmt.Println(Books"Go 语言", "www.runoob.com", "Go 语言教程", 6495407)

    // 也可以使用 key => value 格式
    fmt.Println(Bookstitle: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407)

    // 忽略的字段为 0 或 空
   fmt.Println(Bookstitle: "Go 语言", author: "www.runoob.com")


输出结果为:
Go 语言 www.runoob.com Go 语言教程 6495407
Go 语言 www.runoob.com Go 语言教程 6495407
Go 语言 www.runoob.com  0

访问结构体成员:
如果要访问结构体成员,需要使用点号 . 操作符,格式为:

结构体.成员名
package main

import "fmt"

type Books struct 
   title string
   author string
   subject string
   book_id int


func main() 
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   fmt.Printf( "Book 1 title : %s\\n", Book1.title)
   fmt.Printf( "Book 1 author : %s\\n", Book1.author)
   fmt.Printf( "Book 1 subject : %s\\n", Book1.subject)
   fmt.Printf( "Book 1 book_id : %d\\n", Book1.book_id)

   /* 打印 Book2 信息 */
   fmt.Printf( "Book 2 title : %s\\n", Book2.title)
   fmt.Printf( "Book 2 author : %s\\n", Book2.author)
   fmt.Printf( "Book 2 subject : %s\\n", Book2.subject)
   fmt.Printf( "Book 2 book_id : %d\\n", Book2.book_id)

结构体作为函数参数

package main

import "fmt"

type Books struct 
   title string
   author string
   subject string
   book_id int


func main() 
   var Book1 Books        /* 声明 Book1 为 Books 类型 */
   var Book2 Books        /* 声明 Book2 为 Books 类型 */

   /* book 1 描述 */
   Book1.title = "Go 语言"
   Book1.author = "www.runoob.com"
   Book1.subject = "Go 语言教程"
   Book1.book_id = 6495407

   /* book 2 描述 */
   Book2.title = "Python 教程"
   Book2.author = "www.runoob.com"
   Book2.subject = "Python 语言教程"
   Book2.book_id = 6495700

   /* 打印 Book1 信息 */
   printBook(Book1)

   /* 打印 Book2 信息 */
   printBook(Book2)


func printBook( book Books ) 
   fmt.Printf( "Book title : %s\\n", book.title)
   fmt.Printf( "Book author : %s\\n", book.author)
   fmt.Printf( "Book subject : %s\\n", book.subject)
   fmt.Printf( "Book book_id : %d\\n", book.book_id)

结构体指针

   /* 打印 Book2 信息 */
   printBook(&Book2)

func printBook( book *Books ) <

以上是关于Go语言学习之路的主要内容,如果未能解决你的问题,请参考以下文章

Go语言之路—博客目录

go语言(golang)学习之路

《Go语言精进之路》读书笔记 | 汇总

Go语言学习之路

Go语言学习之路

Go语言学习之路