Go 语言学习零散笔记整理。
零值初始化
同样是声明一个切片,这两种方式有什么区别?
1 | // sl1 这个变量声明了,还没初始化,是 nil 值,和nil比较返回true,底层没有分配内存空间 |
同样是声明一个 map,这两种方式有什么区别?
1 | // 变量 m1 只是声明了但是没有初始化,默认值为 nil,这个时候如果直接对 map 进行赋值,则会导致运行时异常 |
因此在使用 map 之前,必须先对其进行初始化。
引用类型
Go 语言的基本数据类型中,map、slice、channel 这些都是引用类型。
引用类型的特点是,赋值时,不是值传递而是引用传递。
下面通过一个示例来理解:
1 | func main() { |
运行上面的示例代码,输出如下:
1 | 99 |
符合预期。
错误处理
首先明确一个前提:错误不是异常。
常见的错误处理方法是返回 error
,由调用者决定后续如何处理。但是如果是无法恢复的错误,通常会触发 panic
,程序会因此而无法运行,而这个就是异常。
1 | func main() { |
error
是一个接口,它是 Go 原生内置的类型。
errors
是一个包文件,通常用到它的 errors.New
方法用构造一个错误值,赋值给接口。因此通常把 error
作为返回值类型,errors.New()
作为构造 error 类型的返回值的方式之一,fmt.Errorf()
也可以构造。
定义一个新类型
type T1 =T
和 type T1 T
两个语法本质上有什么区别呢?
前者是基于类型别名(Type Alias)定义新类型,后者是通过类型声明(Type define)给原类型起别名。
1 | // type alias |
类型 T 与 string 完全等价。完全等价的意思就是,类型别名并没有定义出新类型,类 T 与 string 实际上就是同一种类型,因此通常会称 类型 T 是基础类型 string 的别名。
1 | // type define |
虽然 T1 和 T2 是不同类型,但因为它们的底层类型都是类型 int,所以它们在本质上是相同的。而本质上相同的两个类型,它们的变量可以通过显式转型进行相互赋值,相反,如果本质上是不同的两个类型,它们的变量间连显式转型都不可能,更不要说相互赋值了。
底层类型这个概念在 Go 语言中有重要作用,通常被用来判断两个类型本质上是否相同(Identical)。
接口类型不能使用指针
下面这样的代码很常见,通常使用第三方依赖时,经常会写出这样的代码。可是,有没有想过一个问题?为什么 http.ResponseWriter
是没有带指针的,而 *http.Request
又带了指针?
1 | type Context struct { |
记住一句话:使用指针可以节省内存,但接口类型不能使用指针。因此定义结构体、作为函数参数时接口类型都是没有指针的,而结构体类型则需要结合实际情况考虑加不加指针。
goroutine 共享变量
下面这段代码,作为 goroutine 运行的闭包会发生什么?
1 | func main() { |
初次使用 goroutine 时,肯定都遇到过这个问题,怎么全部输出的是 c、c、c?
这是因为变量 v 是一个共享变量,存在竞争状态。有两种解决方案:将变量作为参数传递给闭包和使用中间变量。
将变量作为参数传递:
1 | for _, v := range values { |
使用中间变量:
1 | for _, v := range values { |
如何调试 Go
如果使用 Goland 作为开发工具,那么 Go 程序的调试非常简单,不需要额外安装插件,开箱即用。
只需要在对应文件位置,打上断点即可。
如果使用 VsCode 作为开发工具,则需要通过额外安装插件并配置达到调试目的,所以建议直接使用 IDE。
不过需要注意的是,操作系统需要与对应版本对应上,否则是调试不了的。
例如,M1 芯片 不支持amd64,如果刚好安装的是 darwin/amd64
版本,则会提示:
Debugging programs compiled with go version go1.18.1 darwin/amd64 is not supported.
解决方案很简单,直接下载安装 arm64 版本即可。
如何卸载 Go
卸载已经按照好的 Go 非常简单,通常只需要三步:
找到Go 二进制文件的位置,通常是
/usr/local/go
1
2$ which go
/usr/local/go/bin/go删除Golang二进制文件
1
sudo rm -rvf /usr/local/go/
从 PATH 环境变量中删除 Go 二进制文件所在目录
如果是 macOS,则需要多一步删除 /etc/paths.d/go
文件:
1 | $ sudo rm -rvf /etc/paths.d/go |
详情可以查看官方文档