一,GO的安装与配置
官网:https://golang.org/dl/
镜像:https://golang.google.cn/dl/
1,GOPATH
GOPATH在windows上的默认值:%USERPROFILE%/go
Go1.14及之后的版本中启用了Go Module模式之后,不一定非要将代码写到GOPATH目录下,所以也就不需要我们再自己配置GOPATH了
Go1.14之前的版本GOPATH 即为工作目录:本示例设置为 E:\workgo
workgo // my-go为GOPATH目录
-- bin
-- myApp1 // 编译生成
-- myApp2 // 编译生成
-- myApp3 // 编译生成
-- pkg // 依赖包,编译后的归档文件
-- src
-- MyApp1 // 项目1
-- models
-- controllers
-- others
-- main.go
-- MyApp2 // 项目2
-- models
-- controllers
-- others
-- main.go
2,Proxy
2.1,设置代码
默认GoPROXY配置是:GOPROXY=https://proxy.golang.org,direct, https://proxy.golang.org访问不是很可靠,常用的两个代理镜像: 代理一:go env -w GOPROXY=https://goproxy.io,direct 代理二:go env -w GOPROXY=https://goproxy.cn,direct
2.2,设置私仓库
私有库设置,不走代理 go env -w GOPRIVATE=*.gitlab.com,*.gitee.com
2.3,验证包的有效性
go mod vendor,验证包的有效性时,Get https://sum.golang.org/lookup/xxxxxx: dial tcp 216.58.200.49:443: i/o timeout 是因为 sum.golang.org 网站不能访问,可以关闭验证包的有效性 go env -w GOSUMDB=off 也可以使用国内的网站验证包的有效性 go env -w GOSUMDB="sum.golang.google.cn"
3,go环境的常用命令:
go run src/main.go
go build src/main.go
./main.exe
go version
go env
3,项目目录结构
4,开发工具:
4.1,GoLand (关键在于怎么长期使用)
GoLand 下载地址:https://www.jetbrains.com/go/download/other.html
4.2,VS Code
Vs Code 下载地址:https://code.visualstudio.com/Download
Ctrl + Shift + P 安装 go:install 相关命令
5,包管理
1.5版本之前,依赖包放在GOPATH下 1.5版本及之后,采用了vendor机制,主要解决包的版本管理 1.9版本推出了包管理工具,dep 1.11版本推出了包管理工具,modules 简称 mod
初始化一个项目的mod, go mod init <项目名> go.mod定义:
module用来定义包名 require用来定义依赖包及版本 indirect表示间接引用 在goland中可以用alt+enter来下载依赖包
同一个项目的包引用: "xcj.com/gose01/src/mypackage" 不同项目的包引用: a,在go.mod里定义: require "xcj.com/gose02" v0.0.0 replace "xcj.com/gose02" => "../gose02" b,在使用的文件里定义: "xcj.com/gose02/src/testpackage"
指定安装某个版本:go get package@version 例:go get github.com/astaxie/[email protected]
跨平台编译:
winows下编译linux可执行文件: SET CGO_ENABLED=0 // 禁用CGO SET GOOS=linux // 目标平台是linux SET GOARCH=amd64 // 目标处理器架构是amd64
windows下编译苹果可执行文件: SET CGO_ENABLED=0 SET GOOS=darwin SET GOARCH=amd64
变量声明:
var name string var age int var isOk bool
var ( a string b int c bool = true d float32 ) // 通过用小括号包含的方式写到多行 var a, b, c int // 变量a、b、c的类型都是int 若不赋值,用零值来初始化 var x, y, z = true, 10.24, "randy" // 推导出变量x、y、z的类型分别为bool、float64、string var f, err = os.Open(name) // 调用os.Open函数返回一个打开的文件和一个错误信息 短变量: i, j := 0, 1 // 简短声明一组变量,用于函数内部 a,b: = 200,"hello" // 简短声明一组变量,用于函数内部
匿名变量:
定义: func Foo(str string) (int, string) { return 10, str } 调用: x, _ := mypackage.Foo("xcj") _, y := mypackage.Foo("yy") fmt.Println("x=", x) fmt.Println("y=", y)
// iota是go语言的常量计数器,只能在常量的表达式中使用 // iota的行记数,只在当前const内生效 // iota在const关键字出现时将被重置为0 ,主要是用于定义枚举 // const同时声明多个常量时,如果省略了值则表示和上面一行的值相同 const ( n1 = iota n2 = iota n3 = 0 n4 ) const n5 = iota //0
fmt.Println(n1,n2,n3,n4,n5) // 输出结果 0 1 0 0 0
格式化输出:
var people interface{} = struct { name string age int }{"sam", 20} fmt.Printf("%v\n",people) // %v 相应值的默认格式 {sam 20} fmt.Printf("%+v\n",people) // %+v 打印结构体时,会添加字段名 {name:sam age:20} fmt.Printf("%#v\n",people) // %#v 相应值的Go语法表示 struct { name string; age int }{name:"sam", age:20} fmt.Printf("%T\n",people) // %T 相应值的类型的Go语法表示 struct { name string; age int } fmt.Printf("%v%%\n",100) // %% 字面上的百分号,并非值的占位符 100%
go的数据类型:
除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通道(channel)等。
nil是预定义的标识符,代表指针、通道、函数、接口、映射或切片的零值,是预定义好的一个变量
// 浮点数不是一种精确的表达方式 x := 0.1 y := 0.2
res := x + y fmt.Println(res) // 0.30000000000000004 fmt.Println(res == 0.3) // false
数组与切片:
切片可以理解成一种特殊的数组,切片可以改变存储大小,数组是值拷贝而切片是引用
// 切片添加值 //var slice []int = []int{3, 6} //fmt.Println(slice) //slice = append(slice, 1, 2, 3, 5, 8) //fmt.Println(slice)
fmt.Println("数组***********************************") var arr1 [3]int = [3]int{1, 2, 3} var arr2 [3]int = arr1 fmt.Println(arr1, arr2) arr2[0] = 10002 fmt.Println(arr1, arr2)
fmt.Println("切片***********************************") var slice1 []int = []int{1, 2, 3} var slice2 []int = slice1 fmt.Println(slice1, slice2) slice2[0] = 10002 fmt.Println(slice1, slice2)
数组的大小是类型的一部分,数组大小不可改变 var a [4]int=[4]int{1,2,3,4} var a =[4]int{1,2,3,4} a :=[4]int{1,2,3,4}
interface{} 类型数组,可以包含任意类型
让编译器根据初始值的个数自行推断数组的长度 var numArray = [...]int{1, 2}
使用指定索引值的方式来初始化数组 a := [...]int{1: 1, 3: 5} fmt.Println(a) // [0 1 0 5]
多组数组 a := [...][2]string{ {"北京", "上海"}, {"广州", "深圳"}, {"成都", "重庆"}, }
切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针(地址)、切片的长度(len)和切片的容量(cap)。 var a[9]int = [9]int{0,1,2,3,4,5,6,7,8} fmt.Println(a) var b[]int = a[1:2] // 使用数组构建切片 fmt.Println(b) fmt.Println(len(b)) fmt.Println(cap(b))
a := make([]int, 2, 10) fmt.Println(a) //[0 0] var b []int = make([]int, 3)
var citySlice []string citySlice = append(citySlice, "北京")
流程控制:
// if 用法 if score := 65; score >= 90 { fmt.Println("A") } else if score > 75 { fmt.Println("B") } else { fmt.Println("C") }
// for // for循环可以通过break、goto、return、panic语句强制退出循环。 i := 0 for i < 10 { fmt.Println(i) i++ }
// 循环数组 //names:=[4]string{"张三","李四","王五"} //for i,v:=range names{ // fmt.Println(i,v) //}
// 循环切片 //names:=[]string{"张三","李四","王五"} //for i,v:=range names{ // fmt.Println(i,v) //}
// 循环字符串 //for i,v:=range "hello你好"{ // fmt.Printf("%d %q\n",i,v) //}
// map返回键和值 //ages:=map[string]int{ // "张三":20, // "李四":30, //} //for i,v:=range ages{ // fmt.Println(i,v) //}
fallthrough 语法可以执行满足条件的case的下一个case,无条件执行下一个case(穿透)是为了兼容C语言中的case设计的。 s := "a" switch { case s == "a": fmt.Println("a") fallthrough // 无条件执行下一个case(穿透) case s == "b": // 上一个条件满足之后会执行这条语句 fallthrough fmt.Println("b") case s == "c": fmt.Println("c") default: fmt.Println("...") }
goto跳转:
for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { // 设置退出标签 goto breakTag } fmt.Printf("%v-%v\n", i, j) } } return // 标签 breakTag: fmt.Println("结束for循环")
函数作为参数传递:
x11 :=calc(calc(10,20), calc(20,30)) print(x11)
func calc(x, y int) (int) { sum := x + y return sum }
func intSum(x ...int) int { fmt.Println(x) //x是一个切片 sum := 0 for _, v := range x { sum = sum + v } return sum }
我们可以使用type关键字来定义一个函数类型 type calculation func(int, int) int func add(x, y int) int { return x + y }
func sub(x, y int) int { return x - y }
函数作为参数: func add(x, y int) int { return x + y } func calc(x, y int, op func(int, int) int) int { return op(x, y) }
ret2 := calc(10, 20, add) fmt.Println(ret2) //30
闭包指的是一个函数和与其相关的引用环境组合而成的实体
func adder() func(int) int { var x int return func(y int) int { x += y return x } } func main() { var f = adder() // f = func(y int) int{...} fmt.Println(f(10)) //10 fmt.Println(f(20)) //30 fmt.Println(f(30)) //60
f1 := adder() fmt.Println(f1(40)) //40 fmt.Println(f1(50)) //90 }
defer延迟处理,异步处理,最后被defer的语句,最先被执行。 fmt.Println("start") defer fmt.Println(1) defer fmt.Println(2) defer fmt.Println(3) fmt.Println("end")
start end 3 2 1
Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值) Go语言中使用&字符放在变量前面对变量进行“取地址”操作。 int、float、bool、string、array、struct *int、*float、*bool、*string、*array、*struct
//指针取值 a := 10 b := &a // 取变量a的地址,将指针保存到b中 fmt.Printf("type of b:%T\n", b) // type of b:*int c := *b // 指针取值(根据指针去内存取值) fmt.Printf("type of c:%T\n", c) //type of c:int fmt.Printf("value of c:%v\n", c) //value of c:10
func modify1(x int) { x = 100 }
func modify2(x *int) { *x = 100 }
func main() { a := 10 modify1(a) fmt.Println(a) // 10 modify2(&a) fmt.Println(a) // 100 }
// 结构体名字or结构体中的字段名字首字母大写表示公开的、可以被其他包导入,小写表示私有、仅在定义当前结构体的包中可访问 // 使用type和struct关键字来定义结构体 // 方法与函数的区别是, 函数不属于任何类型, 方法属于特定的类型。 //Person 结构体 type Person struct { name string age int8 }
//NewPerson 构造函数 func NewPerson(name string, age int8) *Person { return &Person{ name: name, age: age, } }
//Dream Person做梦的方法 func (p Person) Dream() { fmt.Printf("%s的梦想是学好GO!\n", p.name) }
func main() { p1 := NewPerson("路人A", 25) p1.Dream() }
|
请发表评论