Go 语言上手-基础语言 | 青训营笔记

205 阅读8分钟

image.png

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

Let's go to "Go"

本文分为两部分:Go语言简介,Go语言开发入门

其中Go语言开发入门分开开发环境配置和基础语法,基础语法部分指出了 Go 语言语法的独特之处和要点,适合有一定编程语言基础的小伙伴们阅读,如需学习详细语法请阅读 Go语言圣经 等专业书籍

1.Go 语言简介

1.1 你好,Gopher

image.png 记得这只蓝皮土拨鼠嘛,它便是 Go 的吉祥物:Gopher。

Gopher 由 Renee 创造,它代表 Go 项目和世界各地的 Go 程序员,并且是 Go 世界中最流行的东西之一。

那么这只憨态可掬的土拨鼠能为程序员做些什么呢?

1.2 Go 是一门什么样的语言

Build fast, reliable, and efficient software at scale

  • Go is an open source programming language supported by Google
  • Easy to learn and get started with
  • Built-in concurrency and a robust standard library
  • Growing ecosystem of partners, communities, and tools

Go 语言具有以下特点

  • 高性能、高并发
  • 语法简单、学习曲线平缓
  • 丰富的标准库
  • 完善的工具链
  • 静态编译
  • 跨平台
  • 垃圾回收

当前 Go 被广泛用于高并发场景

2.Go 语言开发入门

2.1 开发环境配置

我的电脑为 archlinux 系统, 所以直接使用 pacman 即可轻松完成环境安装与配置 如果小伙伴可以到官网上学习响应的安装配置教程

Go 语言官网:golang.google.cn/

GoLand 官网:www.jetbrains.com/go/promo/

1.更新系统

$ sudo pacman -Syu

2.安装 Go

$ sudo pacman -S go

3.验证 Go 是否安装成功

$ go version
> go version go1.18.1 linux/amd64

4.安装 Goland

$ sudo pacman -S goland

5.拉取项目

在开始界面点击 Get from VCS ,填入青训营给的练习仓库即可完成项目的 clone

仓库地址:github.com/wangkechun/…

image.png 6.验证开发环境 找到项目下的 go-by-example/example/01-hello/main.go 文件,其中代码如下面所示,没错就是经典的 "hello world",运行它吧!

package main

import (
   "fmt"
)

func main() {
   fmt.Println("hello world")
}

2.2 基础语法

由于本人已有一定编程基础,这里只重点记录了 Go 语言的独特之处,这部分内容主要摘自 Go语言圣经 《The Go Programming Language》,有需要的小伙伴们可以去看看

入门

我们还是以 helloword 为例来入门

package main 

import (
   "fmt"
)

func main() {
   fmt.Println("hello world")
}
  • Go 是一门编译型语言,Go 语言的工具链将源代码及其依赖转换成计算机的指令。在终端中输入 go, 即可获得相关命令信息

image.png

例如,我们可以使用 run 来编译和运行我们编写的 helloworld 程序

$ go run helloworld.go
> hello world
  • Go 语言原生支持 Unicode,它可以处理全世界任何语言的文本
  • Go 语言的代码通过 package 组织,标明该文件属于哪个包
  • Go 语言通过 import 导入包,且必须跟在 package 后
  • Go 一个函数的声明由 func 关键字、函数名、参数列表、返回值列表以及大括号
  • Go 语言在代码格式上采取了很强的态度,gofmt 工具把代码格式化为标准格式

程序结构

命名风格:尽量短小、驼峰式命名

声明

  • var、const、type、func 分别对应变量、常量、类型和函数实体对象的声明

  • 变量类型后置

  • 简短变量声明 a:=1,广泛应用

    • 简短变量声明左边的变量可能并全都是刚刚声明的,如果已经声明过则为赋值行为
    • 简短变量声明语句中必须至少要声明一个新变量
    • 一个指针对应变量在内存中的存储位置,任何类型的指针的零值都是 nil
  • 表达式 new(T) 将创建一个 T 类型的匿名变量,初始化为 T 类型的零值,然后返回变量地址,返回的指针类型 *T,好处是不用专门声明一个临时变量

赋值

  • a = b 即可完成赋值
  • 元组赋值允许同时更新多个变量的值,先对右表达式求值,然后统一更新变量的值
  • 隐式赋值:函数调用、返回语句、符合字面量都有可能产生隐式赋值

类型

  • type 类型名 底层类型 是一个类型声明语句
  • 新命名的类型提供了一个方法,来分隔不同概念的类型,即使底层类型相同也不兼容
  • 类型声明语句一般出现在包一级,因此如果新创建的类型名字的首字符大写,则在外部包也可以使用

包和文件

  • 包和其他语言模块和库概念类似,目的是为了支持模块化、封装、单独编译和代码重用
  • 每个包都对应一个独立的名字空间
  • import 通过全局唯一的导入路径导入包
  • 包的初始化首先解决包级变量的依赖顺序,然后按照包级变量声明出现的顺序依次初始化,排序的工作交给 Go 语言的构建工具来做

作用域: 区分作用域与生命周期

  • 声明语句的作用域对应源代码的一个文本区域,是编译时的属性
  • 声明周期是指程序运行时变量存在的有效时间段,是运行时的概念

基础数据类型

image.png

Go 语言主要有 4 种数据类型:基础类型、复合类型、引用类型、接口类型

基础类型我们主要关注一下几个性质

  • 布尔型并不会隐式转化为数字 0 或 1,必须用一个显式的 if 语句辅助转化
  • 一个字符串是一个不可改变的字节序列,不可修改
  • 常量表达式在编译期计算,而不是运行期。每种常量的潜在类型都是基础类型

复合数据类型

数组

  • 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成

Slice

  • Slice 代表变长的序列,序列每个元素都有相同的元素,可以看成没有固定长度的数组
  • Slice 比较不能用 ==,除了[]byte 类型的 Slice 有 bytes.Equal 函数支持外,其他类型需要自己展开每个元素比较
  • Slice的元素是间接引用,一个固定的Slice在不同的时间可能包含不同的元素值,因为底层的数组元素可能会被修改
  • 必须把 append 结果赋值回原数组, slice 原理:长度+容量+指向数组的指针,容量不够会扩容返回新slice

image.png

Map

  • Map 是一个哈希表的引用 map[K]V, 无序的 key/value对的集合
  • Map 的迭代顺序是不确定的,并且不同的含义函数实现可能导致不同的遍历顺序,每一次的遍历顺序都不同

结构体

  • 结构体不能包含同类型的成员,但是可以包含其指针类型,可以借此实现递归结构
  • 结构体面值两种形式
type user struct {
   name     string
   password string
}

//以成员名字和值来初始化,顺序不重要,如果不出现默认零值
a := user{name: "wang", password: "1024"} 

//要求以结构体成员定义顺序为每个成员指定一个面值
b := user{"wang", "1024"} 
  • 如果结构体全部成员都可以比较,则可以使用 ==
  • 结构体嵌入和匿名成员,我们可以直接访问叶子属性而不需要给出完整的路径

JSON

type userInfo struct {
   Name  string //首字母大写
   Age   int `json:"age"` //默认输出大写,加个 tag, 可以把输出的字段名改成小写
   Hobby []string
}
  • 编组:使用json.Marshal 函数将 Go 数据类型转为 JSON
    • 默认使用 Go 语言结构体成员名字作为 JSON 的对象
    • 选择用大写字母开头的成员名称
  • 解码:使用json.Unmarshal 函数将 JSON 转为 Go 数据类型

image.png

函数

  • 函数声明包括函数名、形参列表、返回值列表(可甚略)、函数体
  • 函数可以有多个返回值,一般返回两个值,第一个为期望的返回值,第二个为出错时的错误信息
  • Go 语言中函数和其他值一样永远类型,可以赋值给其他变量,可以作为参数传递,可以被返回
  • 函数的零值为 nil
  • 在调用普通函数或方法前加上关键字 defer,则当 defer语句被执行时,跟在 defer 后面的函数会被延迟执行,知道包含该 defer 语句的函数执行完毕时,defer后的函数才会被执行。
  • 可以在一个函数中执行多条 defer 语句,它们的执行顺序与声明顺序相反,多用于处理成对的操作
  • 释放资源的 defer 应该直接跟在请求资源语句后面

方法

  • 在函数声明时,在其名字之前放下一个变量,就是一个方法。这个附加的参数会将该函数附加到这种类型上,相当于为这种类型定义的独占的方法。可以类比其他语言的类成员函数
type Point struct{X, Y float64}
// 函数
func Distance(p, q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y)
}

//方法
func (p Point) Distance(q Point) float64 {
    return math.Hypot(q.X-p.X, q.Y-p.Y)
}

引用参考

Go 官网:golang.google.cn/

Go 语言圣经:books.studygolang.com/gopl-zh/

关于 Gopher:learnku.com/docs/go-blo…