学习go的安装环境和基本配置还有基础知识

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
全栈老韩
全栈工程师,擅长iOS App开发、前端(vue、react、nuxt、小程序&Taro)开发、Flutter、React Native、后端(midwayjs、golang、express、koa)开发、docker容器、seo优化等。

一、go安装和环境配置

1. 安装

方式一:软件包安装
进入官网:https://go.dev/dl/,选择自己的电脑系统,下载软件包安装
方式二: Mac电脑中使用brew

terminal 复制代码
brew install go

windows略

2. 查看和配置环境

terminal 复制代码
// 查看go的环境配置变量,主要看GOPATH、GOROOT、GOBIN
go env

// 如果不想使用默认的GOPATH配置路径,可自行设置GOPATH
go env -w GOPATH=xxxx  // xxxx为路径,比如/usr/local/go

// GOBIN也需要设置一下,使用GOPATH路径下的bin目录即可
  1. src // 这里面存放我们自己编写的go项目,往往以域名为文件夹名,然后以项目名作为二级文件夹名
    比如:src/baidu.com/baidu_cloud(baidu.com为域名,下面有一个baidu_cloud的工程项目)
  2. pkg // 见后面介绍
  3. bin // 见后面介绍

3. 修改go镜像

由于墙,国内推荐使用七牛云的镜像服务,查看其官网指南:https://goproxy.cn/
go镜像服务截图

4. 代码编辑器IDE

对于go,官方IDE是goland,可以到官网下载:官网IDE下载
我个人推荐使用vscode,在vscode中安装使用几个好用的扩展:
我推荐的开发go的vs插件

二、go程序基本框架

1. GOPATH解释

1.src文件夹:存放源码;
2.bin文件夹:存编译出的产物;
3.pkg文件夹:存缓存的库。

  • 应该放在GOPATH指向的目录
terminal 复制代码
// 查看GOPATH指向的目录位置
go env | grep GOPATH
  • 补充
    GOROOT:go编译源码根目录;
    GOPATH: go工程的根目录;GOPATH下应该要有src、bin、pkg这3个文件夹(没有的话可以新建这几个文件夹),编写的工程代码需放在src中,比如go项目工程go_test,目录应该如: $GOPATH/src/go_test。
    GOBIN: go工程的bin目录,存放二进制可执行文件;

  • 每一个go文件,都以go为扩展名;

  • go文件中都有一个包名,作为命名空间:

test.go 复制代码
pacakage main

func main() {
    
}

2. 代码工程 & mod

  1. 程序的入口文件都是main.go
  2. 然后可以新建其他的文件夹,比如controller、model、services、utils等
  3. 初始化mod,mod中有我们自己项目中所需引入的库,类似于依赖配置文件。
    打开命令行终端,进入在main.go同级目录,执行以下命令:
terminal 复制代码
go mod init baidu_cloud //这里以baidu_cloud为工程名字作为示例
  1. 生成mod文件后,之后基本不用管mod

3. 引入包

xxx.go 复制代码
import "fmt" // 在go文件中引入标准库

当需要引入其他框架时,比如gorm框架,需要在项目根目录,即mod所在目录下,执行终端命令:

terminal 复制代码
go get -u gorm.io/gorm

执行命令成功后,mod文件中会自动引入这个库版本等信息,工程中就可以直接引用使用。
其他go框架,参照其对应的github使用方式即可。

4. go常用命令

terminal 复制代码
go run xxx.go // 编译运行某个文件

go run *.go // 所有go文件

go build -o xxx.exe xxx.go // 编译成windows上的程序

go env // 查看go的环境配置信息

go env -w GOPATH=/usr/local/go // 修改env中某个配置变量的值,这里以GOPATH为示例

三、基本语法

  1. 变量声明:
xxx.go 复制代码
// 自动类型推断
name := "自动类型推断,所有语句不需要分号结尾"
age := 14

list := [10]int{1, 2, 3}; // 固定长度数组
arr  := []int{}; // 可变长度数组

// 先声明,后赋值
var nickname: string
nickname = "可以声明了再赋值"

// 声明多个并赋值
name, age := "姓名", 14

// 可以不用加小括号
// 大括号的 { 要紧跟在代码行右侧,再换行写大括号中的代码
con := 4
if con > 3 {
    fmt.println("true")
}

// 数字变量,只有后置运算符,没有c语言中的前置运算符
iterator := 1 // 声明了一个1
iterator++ // 这行必须单独一行,不能放在if或者其他代码行中
++iterator // 会报错
  1. 数组
xxx.go 复制代码
list := []str{"元素1", "元素2"}

// 获取数组长度
fmt.printf("数组长度:%d", len(list))

// 第一种常规循环
for i:=0; i<len(); i++ {
    
}

// 第二种循环 for - range
for key, value := range list {
    fmt.printf("数组长度:%c", key, ", 值是:%c", value)
}

// 如果要忽略其中某一个值,使用_下划线代替即可
for _, value := range list {
    fmt.printf("值是:%c", value)
}
  1. 数组的length和capacity(长度len和容量cap)
xxx.go 复制代码
list := []int{1, 2}

println("长度是:", len(list)) // 2
println("容量是:", cap(list)) // 2

// 数组添加
list = append(list, [3, 4, 5])

fmt.println("长度是:", len(list)) // 4
fmt.println("容量是:", cap(list)) // 8

当数组新增加的数量,超过初始容量时,可变数组的容量会增加为初始容量的2倍,当容量越来越大时,可能到不了2倍

  1. 数组切片
xxx.go 复制代码
list := []int{1, 2, 3, 4}

sliceList = list[0:2] // 取list的第0位到第2位的元素,半闭合数组 0<= slice <2

sliceList2 = list[:4] // 默认为 0 <= ... <4

sliceList2 = list[2:] // 默认为 2 <= ... 

// warning:当修改切片中的某一个数据时,会影响到原数组。
// 想要切片独立于原数组,那么需要使用copy函数

welString := "hello world"[6:]
for i:=0; i<len(welString); i++ {
    
}

copy操作:

xxx.go 复制代码
list := []int{1, 2, 3, 4}

list_copy := make([]int, len(list))

copy(list_copy, list[:]) // 表示把list全长的切片,拷贝到list_copy,
// 因为copy函数第二位要求是切片类型

make创建指定length和capacity的切片:

xxx.go 复制代码
str := make([]string, 10, 15) // 创建一个默认长度为10,容量为15的切片, 
// 15所代表的第3个形参不是必须填写的,如果没写cap,默认和len一样
  1. 函数声明
xxx.go 复制代码
// 不带返回值
func main() {
    
}

// 带返回值
func doSomething() string {
    return "返回值是xxxxx"
}
  1. 指针
xxx.go 复制代码
// 指针操作
name := "Li lei"
namePtr = &name

fmt.println("指针指向的内容是:", *namePtr)

// 不同于c语言,go还可以取到栈空间的指针
func test() *int {
    num := 1
    return &num // 一般情况下,程序执行完毕,栈空间中的变量会被释放掉,
    // 但是go会判断如果是需要使用到的栈变量,会把变量存到堆上
}

fmt.println("指针的内容是:", *test()) // 1
  1. map字典
xxx.go 复制代码
// 推断式声明 - 推荐使用
dict := make(map(int)string)
// 或者
dict := make(map(int)string, 10) // 给定长度

// 先声明,再赋值
var dict map(int)string
dict = make(map(int)string)

// 赋值
dict[0] = "first"
dict[1] = "second"

// 读取
fmt.println("值是:", dict[0]) // first
fmt.println("超过容量的值是:", dict[100]) // 空,当读取的key不在容量内时,返回空,不报错

// 循环
for key, value := range dict {
    fmt.println("key是:", key, ", value是:", value)
}

// 判断map中是否有这个key存在(由于读取不存在的key也不报错)
value, ok := dict[0]
if ok {
    fmt.println("value是:", value) // first
} else {
    fmt.println("value是:", value) // 空
}

// 删除某一个值
delete(dict, 0)
delete(dict, 100) // 删除不存在的,也不会报错
fmt.Println("删除后:", dict) // map[1 : second]

// 并发任务处理的时候,需要对map上锁

暂无评论,快来发表第一条评论吧