基本特性
原创大约 5 分钟
以下代码均基于GoLand开发。
GOPATH和GOMODULE的区别
GOPATH
是Go语言在1.14
版本之前的包依赖管理方式,作为工作目录,它规定必须具有如下的工作目录。
bin
:存放编译后生成的二进制可执行文件。pkg
:存放编译后生成的.a
文件。src
:存放项目的源代码,可以是你自己写的代码,也可以是你go get
下载的包。
但GOPATH
用起来非常不方便,这是历史遗留问题,现在可以不用理会它。
从1.11
版本开始,go env
多了个环境变量:GO111MODULE
。
使用GOMODULE
模式后,项目目录下会多生成两个文件:go.mod
和go.sum
。
go.mod
主要用于保存模块的引用路径、版本、项目所需的直接依赖包及其版本go.sum
则是保存go.mod
中相关模块、依赖包和文件的校验和。
这两个文件是Go自动管理和维护的,不用人为去修改它。
除此外,GOMODULE
模式还提供了一系列的go mod
命令,用于更好地使用和管理包依赖。
iota
package main
import "fmt"
func main() {
// iota是一个关键字,是特殊常量,可以认为是一个被编译器修改的常量
// 它相当于是一个递增的常量,iota的初始值为0,每次递增1
const (
ERR1 = iota
ERR2 = iota
ERR3 = iota
ERR4 = iota
)
// 另一种iota的形式
const (
ERR5 = iota
ERR6
ERR7
ERR8
)
const (
ERR9 = iota
ERR10
ERR11
ERR12 = "xiangwang"
ERR13
ERR14 = iota
)
fmt.Println(ERR9, ERR10, ERR11, ERR12, ERR13, ERR14)
/*
iota的值与行序有关,它的值是从0开始递增的,且每增加一行就自增1
每次出现const关键字时,iota的值初始化为0
*/
// 匿名变量
// 匿名变量可以不赋值,但是必须使用_来接收
// 有时候函数有多个返回值,但只想用其中的几个而非全部,就可以用匿名变量来作为占位符使用
_, ok := a()
if ok {
fmt.Println("ok")
}
var age uint8 = 30
fmt.Println(age)
}
func a() (int, bool) {
return 0, true
}
goproxy镜像
查看环境配置命令。
go env
设置下面两个地方。
go env -w GO111MODULE='on'
go env -w GOPROXY='https://goproxy.cn,direct'
第一个是设置Go的包依赖管理方式为GOMODULE
,第二个是GOPROXY
,可以设为goproxy.cn
或者goproxy.io
。
如果不设置GOPROXY
,那么在Gin框架可能无法下载。
go get
相关命令。
go get
用于下载依赖。
go get github.com/go-redis/redis/v8
- 指定使用的版本。
go get github.com/go-redis/redis/v8@1.8.0
go mod help
:查看相关go mod
命令。go mod tidy
:清理依赖。
错误处理
package main
import (
"errors"
"fmt"
"strconv"
)
func testError() (int, error) {
// 真正返回一个error的方法:errors.New(),类似于Java的 throw new RuntimeException();
return 0, errors.New("this is an error")
}
func testPanic() (int, error) {
// go语言不推荐使用panic,因为panic会直接退出程序
// 程序会从这里退出,并抛出异常
panic("this is an panic")
return 0, errors.New("this is an error")
}
func testRecover() (int, error) {
// 函数肯定会发生panic,所以需要recover来捕获
// 1. defer要放在 pairs["name"] = "bear" 之前定义,否则无法执行
// 2. recover也只有在defer中才会生效
// 3. recover捕获异常后,逻辑并不会恢复
defer func() {
if err := recover(); err != nil {
fmt.Println("testRecover(): ", err)
}
}()
var pairs map[string]string
pairs["name"] = "bear"
return 0, errors.New("this is an error")
}
/**
* go语言的错误处理的理念:go设计者认为必须处理error
* 因此开发者需要通过返回值(也就是增加一个错误值error)的方式告诉调用者,函数是否调用成功
* error、panic、recover
*
*/
func main() {
if _, err1 := strconv.Atoi("hello"); err1 != nil {
fmt.Println(err1)
}
if _, err2 := testError(); err2 != nil {
fmt.Println(err2)
}
// panic是一个内置函数,它会停止当前函数的执行
// 类似于java中的“throws exception”抛出一个异常,但go不推荐随便使用panic
//if _, err3 := testPanic(); err3 != nil {
// fmt.Println(err3)
//}
// 适用于panic的场景包括:
// 启动服务时,配置文件读取失败、数据库、网络、中间件或第三方依赖连接失败
// 此时就需要抛出异常,让调用方来处理
// 但总有不小心的时候,例如下面的代码
// pairs未被及时初始化
//var pairs map[string]string
//pairs["name"] = "go"
//// 此时就会出现 panic: assignment to entry in nil map
//fmt.Println(pairs["name"])
// go为了避免这种情况发生,提供了recover函数
// recover能捕获到panic,并返回panic的值
if _, err3 := testRecover(); err3 != nil {
fmt.Println(err3)
}
}
type关键字
package main
import (
"fmt"
"strconv"
)
func main() {
// type关键字
type (
// 1. 定义结构体
Person struct {
name string
age int
}
// 2. 定义接口
MyInterface interface {
Method()
}
// 3. 定义函数
funcType func(int) int
// 4. 定义类型别名
MyInt = int
// 5. 类型定义,用于扩展原类型的能力
MyString string
// 6. 类型判断
// 7. 类型断言
)
// 应用别名
var a MyInt = 1
fmt.Printf("%T", a)
fmt.Println()
var str MyString = "1"
fmt.Printf("%T", str)
// 自定义类型无法实现转换,只有通过类型别名,或者强制类型转换
if _, v := strconv.Atoi(string(str)); v != nil {
fmt.Println(v)
}
fmt.Println()
// 类型判断
var i interface{} = 1
switch i.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
}
// 类型断言
var i2 interface{} = 1
switch v := i2.(type) {
case int:
fmt.Println(v)
case string:
fmt.Println(v)
}
}
感谢支持
更多内容,请移步《超级个体》。