Go 环境准备
本文主要讲解的是在windows上安装Go语言的环境和配置环境变量
下载 Go 环境
- 首先到 Go 的官网找到想要的版本下载
- 放到自己定义的目录下,然后解压
配置环境变量
得到完整的 Go 环境之后,需要配置 Go 的环境变量,右击此电脑–>属性–>高级系统设置–>环境变量,打开环境变量设置窗口。
需要新建两个环境变量配置
一个是 GOROOT ,这个就是 Go 环境所在目录的配置。
另一个是 GOPATH ,这个是 Go 项目的工作目录,你以后开发的代码就写在这个文件夹中。
GOROOT 环境变量配置
1、为了使所有的计算机用户都可以使用 Go 环境,我们就在系统变量之中配置。点击系统变量下的新建,在变量名一栏输入 GOROOT ,在变量值一栏输入你解压文件所在的目录。最后点击确定,就将 GOROOT 新建完毕。
2、然后将新建的GOROOT配置到 Path 这个环境变量中去,在系统变量中找到 Path,点击编辑->新建,输入%GOROOT%\bin,点击确定。并将所有母窗口的确定全部点下,确保环境变量生效。
GOPATH环境变量配置
GOPATH 和 GOROOT 的配置略有不同,建议配置两个GOPATH 目录,第一个用于放 Go 语言的第三方包,第二个用于放自己的开发代码。
点击系统变量下的新建,在变量名一栏输入GOPATH,在变量值一栏输入任意两个目录,中间用英文分号隔开。
示例:D:\go\library;D:\go\workspace
检验配置
windows+R 输入 cmd 打开终端,输入go version,如果输出如下图所示,则安装成功。
#查看Go版本
go version
#查看Go环境变量
go env
Go 基础语法
Go 特点
- 高性能、高并发
- 语法简单、学习曲线平缓,上手容易
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
如 Go 只需要十行代码就能实现一个 HTTP 服务器
package main
import (
"net/http"
)
func main() {
http.Handle("/", http.FileServer(http.Dir(".")))
http.ListenAndServe(":8080", nil)
}
基础语法
数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。
Go 语言按类别有以下几种数据类型:
变量声明
- 使用关键字var来声明一个变量,语法为:var variableName dataType
- 变量名必须以字母或下划线开头,可以包含字母、数字和下划线,但不能使用Go的关键字。
- 可以一次性声明多个变量,例如:var x, y int
- 如果声明时未初始化变量,则变量会被赋予其数据类型的零值,比如:int类型的零值是0,string类型的零值是空字符串""。
- 可以使用短变量声明来创建并初始化变量,语法为:variableName := value
- 在Go中,变量声明后必须使用,否则会导致编译错误。如果想要声明一个变量但不使用它,可以使用下划线 _ 来代替变量名,表示该变量被丢弃,不会占用内存空间。
# 方式一
var a = "initial"
var a int = 2
# 方式二
f := 1
常量声明
- 使用关键字const来声明常量,语法为:const constantName dataType = value
- 常量的值在声明时必须初始化,并且一旦赋值不能再修改。
- 常量可以是字符、字符串、布尔值或数值类型(整数、浮点数)。
- 常量名的命名规则与变量相同,以字母或下划线开头,可以包含字母、数字和下划线,但不能使用Go的关键字。
- 常量的值必须是一个编译时可以确定的表达式,例如:const PI = 3.14
- 常量必须在声明时初始化,并且其值在程序运行期间不能改变。
const a = 1
const s string = "constant"
条件语句
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if num := 9;num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
循环语句
Go 里面只有 for 循环
for {
fmt.Println("loop")
break
}
for i := 1; i < 9;i++ {
fmt.Println(i)
}
i := 1
for i <= 3 {
fmt.Println(i)
i = i+1
}
switch
Go 中 switch 在执行完某个 case 之后会直接退出,不需要使用 break
func main() {
a:=2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3 ,4:
fmt.Println("three or four")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("it is before noon")
default:
fmt.Println("it is after noon")
}
}
数组
数组长度固定在真实的业务场景下不常用
var a [5]int
a[4] = 2
b := [5]int{1,2,3,4,5}
var twoD [2][3]int
切片 slice
切片长度可变,常用于真实业务场景下
s := make([]string, 2)
s[0] = "a"
s[1] = "b"
fmt.Println("len:", len(s)) // 2
s = append(s, "c")
s = append(s, "d", "e")
fmt.Println(s) // [a b c d e]
c := make([]string, len(s))
copy(c, s)
fmt.Println(c) // [a b c d e]
fmt.Println(s[2:4]) // [c d]
fmt.Println(s[:4]) // [a b c d]
fmt.Println(s[2:]) // [c d e]
g := []string{"g", "o", "o", "d"}
fmt.Println(g) // [g o o d]
map
实际开发中使用最频繁的数据结构,放入 map 的数据完全无序
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(lem(m)) // 2
fmt.Println(m["one"]) // 1
fmt.Println(m["unkonw"]) // 0
# ok 用于接收 map 中是否有该 key
r, ok := m["unkonw"]
fmt.Println(r, ok) // 0 false
delete(m, "one")
m2 := map[string]int{"one":1, "two":2}
var m3 := map[string]int{"one":1, "two":2}
range
主要用于简化遍历过程
nums := []int{1,2,3,4}
sum := 0
for i, num := range nums {
sum += num
fmt.Println(i)
}
for _, num := range nums {
sum += num
}
m := map[string]string{"a":"A", "b":"B"}
for k, v := range m {
fmt.Println(k, v) // b B;a A
}
for k := range m {
fmt.Println("key", k) // key a;key b
}
函数 func
在实际的业务逻辑代码中,函数返回多个值,第一个值为真实返回值,第二个为错误信息
# 函数名 参数 返回值类型
func add(a int, b int) int {
return a + b
}
func add(a, b int) int {
return a + b
}
func exist(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok;
}
func main() {
res := add(1,2)
fmt.Println(res) // 3
v, ok := exist(map[string]string{"a":"A"}, "a")
fmt.Println(v, ok) // A True
}
指针 point
Go 初步支持指针,但相比于 C 或 C++,其支持的操作非常有限
func add2(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 2
add2(n)
fmt.Println(n) // 2
add2ptr(&n)
fmt.Println(n) // 4
}
结构体
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt.Println(checkPassword(a, "haha")) // false
fmt.Println(checkPassword2(&a, "haha")) // false
}
func checkPassword(u user, password string) bool {
return u.password == password
}
结构体方法
package main
import "fmt"
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
错误处理
Go 中常使用一个单独的返回值来传递错误信息,不同于Java中的异常,Go 语言能够很清晰的知道哪个函数返回了错误,可以用简单的 if-else 来处理错误,出现错误返回值和错误信息,没有错误返回值和nil
package main
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
字符串操作
在标准库 strings 包里有很多处理字符串的函数
注意:一个中文可能对应多个字符
package main
import (
"fmt"
"strings"
)
func main() {
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.HasPrefix(a, "he")) // true
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
b := "你好"
fmt.Println(len(b)) // 6
}
字符串格式化
package main
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
// 不管什么类型都是使用 %v,可以通过加 +、# 得到更详细的输出
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f) // 3.141592653
fmt.Printf("%.2f\n", f) // 3.14
}
JSON 处理
进行 JSON 处理时要保证结构体每个字段首字母大写
package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
// 序列化
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(buf) // [123 34 78 97...]
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
时间处理
Go 中最常用的时间处理函数是 time.Now() 获取当前时间
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
// 构造带时区的时间
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
// 格式化
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
// 对两个时间做减法
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
// 获取时间戳
fmt.Println(now.Unix()) // 1648738080
}
数字解析
字符串与数字之间的转换
package main
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) // 1.234
// ParseInt 参数1 字符串 参数2 进制(0的话自动推测) 参数3 64位精度
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) // 111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) // 123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}
进程信息
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
// go run example/20-env/main.go a b c d
fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
// 获取环境变量
fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
// 写入环境变量
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
}